From b01884595092b2e49a297dc0344bd6e20942af20 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 07 2019 10:41:39 +0000 Subject: import ipa-4.7.1-11.module+el8+2843+a16c4825 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df10876 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/freeipa-4.7.1.tar.gz diff --git a/.ipa.metadata b/.ipa.metadata new file mode 100644 index 0000000..1251b08 --- /dev/null +++ b/.ipa.metadata @@ -0,0 +1 @@ +7c147ac996f43e83901de707958f72f795b2ce30 SOURCES/freeipa-4.7.1.tar.gz diff --git a/SOURCES/0001-No-need-to-call-rhel-specific-domainname-service.patch b/SOURCES/0001-No-need-to-call-rhel-specific-domainname-service.patch new file mode 100644 index 0000000..bcc4ceb --- /dev/null +++ b/SOURCES/0001-No-need-to-call-rhel-specific-domainname-service.patch @@ -0,0 +1,32 @@ +From b3378c32603e83ea3d4651cee3af99e644a30457 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Fri, 20 Jul 2018 11:06:55 -0400 +Subject: [PATCH] No need to call rhel-specific domainname service + +It was moved upstream into hostname package which named it +nis-domainname. When it was in the initscripts package there were +separate fedora-domainname and rhel-domainname services. + +From F29+ it will be nis-domainname. We can use that as well in +RHEL 8. +--- + ipaplatform/rhel/services.py | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/ipaplatform/rhel/services.py b/ipaplatform/rhel/services.py +index 1403d08..06fa633 100644 +--- a/ipaplatform/rhel/services.py ++++ b/ipaplatform/rhel/services.py +@@ -30,9 +30,6 @@ from ipaplatform.redhat import services as redhat_services + # to their actual systemd service names + rhel_system_units = redhat_services.redhat_system_units + +-# Service that sets domainname on RHEL is called rhel-domainname.service +-rhel_system_units['domainname'] = 'rhel-domainname.service' +- + + # Service classes that implement RHEL-specific behaviour + +-- +2.13.6 + diff --git a/SOURCES/0002-freeipa-4.7.0-ipaclient-Remove-no-sssd-and-noac-options_rhbz#1614301.patch b/SOURCES/0002-freeipa-4.7.0-ipaclient-Remove-no-sssd-and-noac-options_rhbz#1614301.patch new file mode 100644 index 0000000..7447a08 --- /dev/null +++ b/SOURCES/0002-freeipa-4.7.0-ipaclient-Remove-no-sssd-and-noac-options_rhbz#1614301.patch @@ -0,0 +1,77 @@ +From c5cdd5a5f01306b3a70354d34079efe64565aa69 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Thu, 9 Aug 2018 12:05:26 +0200 +Subject: ipaclient: Remove --no-sssd and --no-ac options + +Client installation with --no-sssd option has already beeen deprecated +with https://pagure.io/freeipa/issue/5860. Authconfig support has been +removed, therefore --no-ac option can be removed also. + +ipatests/test_integration/test_authselect.py: Skip no_sssd and no_ac tests. + +See: https://pagure.io/freeipa/issue/7671 +Signed-off-by: Thomas Woerner +Reviewed-By: Christian Heimes +--- + ipaclient/install/client.py | 6 +----- + ipaclient/install/sssd.py | 9 +-------- + ipatests/test_integration/test_authselect.py | 2 ++ + 3 files changed, 4 insertions(+), 13 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 627351ac2..800a46734 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -3709,11 +3709,7 @@ class ClientInstall(ClientInstallInterface, + def prompt_password(self): + return self.interactive + +- no_ac = knob( +- None, +- description="do not modify the nsswitch.conf and PAM configuration", +- cli_names='--noac', +- ) ++ no_ac = False + + force = knob( + None, +diff --git a/ipaclient/install/sssd.py b/ipaclient/install/sssd.py +index b20abde56..98b850464 100644 +--- a/ipaclient/install/sssd.py ++++ b/ipaclient/install/sssd.py +@@ -43,11 +43,4 @@ class SSSDInstallInterface(service.ServiceInstallInterface): + ) + preserve_sssd = enroll_only(preserve_sssd) + +- no_sssd = knob( +- None, +- deprecated=True, +- description="Do not configure the client to use SSSD for " +- "authentication", +- cli_names=[None, '-S'], +- ) +- no_sssd = enroll_only(no_sssd) ++ no_sssd = False +diff --git a/ipatests/test_integration/test_authselect.py b/ipatests/test_integration/test_authselect.py +index fa9b20265..ebf3d9892 100644 +--- a/ipatests/test_integration/test_authselect.py ++++ b/ipatests/test_integration/test_authselect.py +@@ -88,6 +88,7 @@ class TestClientInstallation(IntegrationTest): + ['ipa-client-install', '--uninstall', '-U'], + raiseonerr=False) + ++ @pytest.mark.skip(reason="Option --no-sssd has been removed") + def test_install_client_no_sssd(self): + """ + Test client installation with --no-sssd option. +@@ -98,6 +99,7 @@ class TestClientInstallation(IntegrationTest): + msg = "Option '--no-sssd' is incompatible with the 'authselect' tool" + assert msg in result.stderr_text + ++ @pytest.mark.skip(reason="Option --noac has been removed") + def test_install_client_no_ac(self): + """ + Test client installation with --noac option. +-- +2.17.1 + diff --git a/SOURCES/0003-adtrust-define-Guests-mapping.patch b/SOURCES/0003-adtrust-define-Guests-mapping.patch new file mode 100644 index 0000000..ab55aeb --- /dev/null +++ b/SOURCES/0003-adtrust-define-Guests-mapping.patch @@ -0,0 +1,50 @@ +From 1ef0fe8bb824282c2f48417efda3a60e7c1bf580 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 9 Oct 2018 17:21:37 +0300 +Subject: [PATCH] adtrust: define Guests mapping after creating cifs/ principal + +All Samba utilities load passdb modules from the configuration file. As +result, 'net groupmap' call would try to initialize ipasam passdb module +and that one would try to connect to LDAP using Kerberos authentication. + +We should be running it after cifs/ principal is actually created in +ipa-adtrust-install or otherwise setting up group mapping will fail. + +This only affects new installations. For older ones 'net groupmap' would +work just fine because adtrust is already configured and all principals +exist already. + +A re-run of 'ipa-server-upgrade' is a workaround too but better to fix +the initial setup. + +Related: https://pagure.io/freeipa/issue/7705 +Reviewed-By: Rob Crittenden +--- + ipaserver/install/adtrustinstance.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index 46c4ad663..da16748cf 100644 +--- a/ipaserver/install/adtrustinstance.py ++++ b/ipaserver/install/adtrustinstance.py +@@ -837,8 +837,6 @@ class ADTRUSTInstance(service.Service): + 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("map BUILTIN\\Guests to nobody group", +- self.__map_Guests_to_nobody) + self.step("adding cifs Kerberos principal", + self.request_service_keytab) + self.step("adding cifs and host Kerberos principals to the adtrust agents group", \ +@@ -850,6 +848,8 @@ class ADTRUSTInstance(service.Service): + self.step("updating Kerberos config", self.__update_krb5_conf) + self.step("activating CLDAP plugin", self.__add_cldap_module) + self.step("activating sidgen task", self.__add_sidgen_task) ++ self.step("map BUILTIN\\Guests to nobody group", ++ self.__map_Guests_to_nobody) + self.step("configuring smbd to start on boot", self.__enable) + self.step("adding special DNS service records", \ + self.__add_dns_service_records) +-- +2.17.1 + diff --git a/SOURCES/0004-freeipa-4.7.1-Find_orphan_automember_rules_rhbz#1638373.patch b/SOURCES/0004-freeipa-4.7.1-Find_orphan_automember_rules_rhbz#1638373.patch new file mode 100644 index 0000000..d650aef --- /dev/null +++ b/SOURCES/0004-freeipa-4.7.1-Find_orphan_automember_rules_rhbz#1638373.patch @@ -0,0 +1,209 @@ +From 67875c3b75ad1af493ff5930f9c5fd5e9797b775 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Oct 12 2018 07:50:29 +0000 +Subject: Find orphan automember rules + + +If groups or hostgroups have been removed after automember rules have been +created using them, then automember-rebuild, automember-add, host-add and +more commands could fail. + +A new command has been added to the ipa tool: + + ipa automember-find-orphans --type={hostgroup,group} [--remove] + +This command retuns the list of orphan automember rules in the same way as +automember-find. With the --remove option the orphan rules are also removed. + +The IPA API version has been increased and a test case has been added. + +Using ideas from a patch by: Rob Crittenden + +See: https://pagure.io/freeipa/issue/6476 +Signed-off-by: Thomas Woerner +Reviewed-By: Christian Heimes +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Florence Blanc-Renaud + +--- + +diff --git a/API.txt b/API.txt +index 49216cb..93e1a38 100644 +--- a/API.txt ++++ b/API.txt +@@ -186,6 +186,20 @@ output: Output('count', type=[]) + output: ListOfEntries('result') + output: Output('summary', type=[, ]) + output: Output('truncated', type=[]) ++command: automember_find_orphans/1 ++args: 1,7,4 ++arg: Str('criteria?') ++option: Flag('all', autofill=True, cli_name='all', default=False) ++option: Str('description?', autofill=False, cli_name='desc') ++option: Flag('pkey_only?', autofill=True, default=False) ++option: Flag('raw', autofill=True, cli_name='raw', default=False) ++option: Flag('remove?', autofill=True, default=False) ++option: StrEnum('type', values=[u'group', u'hostgroup']) ++option: Str('version?') ++output: Output('count', type=[]) ++output: ListOfEntries('result') ++output: Output('summary', type=[, ]) ++output: Output('truncated', type=[]) + command: automember_mod/1 + args: 1,9,3 + arg: Str('cn', cli_name='automember_rule') +@@ -6503,6 +6517,7 @@ default: automember_default_group_set/1 + default: automember_default_group_show/1 + default: automember_del/1 + default: automember_find/1 ++default: automember_find_orphans/1 + default: automember_mod/1 + default: automember_rebuild/1 + default: automember_remove_condition/1 +diff --git a/VERSION.m4 b/VERSION.m4 +index f437ef0..9d5532c 100644 +--- a/VERSION.m4 ++++ b/VERSION.m4 +@@ -83,8 +83,8 @@ define(IPA_DATA_VERSION, 20100614120000) + # # + ######################################################## + define(IPA_API_VERSION_MAJOR, 2) +-define(IPA_API_VERSION_MINOR, 229) +-# Last change: Added the Certificate parameter ++define(IPA_API_VERSION_MINOR, 230) ++# Last change: Added `automember-find-orphans' command + + + ######################################################## +diff --git a/ipaserver/plugins/automember.py b/ipaserver/plugins/automember.py +index a502aea..a7f468d 100644 +--- a/ipaserver/plugins/automember.py ++++ b/ipaserver/plugins/automember.py +@@ -117,6 +117,11 @@ EXAMPLES: + Find all of the automember rules: + ipa automember-find + """) + _(""" ++ Find all of the orphan automember rules: ++ ipa automember-find-orphans --type=hostgroup ++ Find all of the orphan automember rules and remove them: ++ ipa automember-find-orphans --type=hostgroup --remove ++""") + _(""" + Display a automember rule: + ipa automember-show --type=hostgroup webservers + ipa automember-show --type=group devel +@@ -817,3 +822,58 @@ class automember_rebuild(Method): + result=result, + summary=unicode(summary), + value=pkey_to_value(None, options)) ++ ++ ++@register() ++class automember_find_orphans(LDAPSearch): ++ __doc__ = _(""" ++ Search for orphan automember rules. The command might need to be run as ++ a privileged user user to get all orphan rules. ++ """) ++ takes_options = group_type + ( ++ Flag( ++ 'remove?', ++ doc=_("Remove orphan automember rules"), ++ ), ++ ) ++ ++ msg_summary = ngettext( ++ '%(count)d rules matched', '%(count)d rules matched', 0 ++ ) ++ ++ def execute(self, *keys, **options): ++ results = super(automember_find_orphans, self).execute(*keys, ++ **options) ++ ++ remove_option = options.get('remove') ++ pkey_only = options.get('pkey_only', False) ++ ldap = self.obj.backend ++ orphans = [] ++ for entry in results["result"]: ++ am_dn_entry = entry['automembertargetgroup'][0] ++ # Make DN for --raw option ++ if not isinstance(am_dn_entry, DN): ++ am_dn_entry = DN(am_dn_entry) ++ try: ++ ldap.get_entry(am_dn_entry) ++ except errors.NotFound: ++ if pkey_only: ++ # For pkey_only remove automembertargetgroup ++ del(entry['automembertargetgroup']) ++ orphans.append(entry) ++ if remove_option: ++ ldap.delete_entry(entry['dn']) ++ ++ results["result"][:] = orphans ++ results["count"] = len(orphans) ++ return results ++ ++ def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, ++ **options): ++ assert isinstance(base_dn, DN) ++ scope = ldap.SCOPE_SUBTREE ++ ndn = DN(('cn', options['type']), base_dn) ++ if options.get('pkey_only', False): ++ # For pkey_only add automembertargetgroup ++ attrs_list.append('automembertargetgroup') ++ return filters, ndn, scope +diff --git a/ipatests/test_xmlrpc/test_automember_plugin.py b/ipatests/test_xmlrpc/test_automember_plugin.py +index ffbc911..c83e11a 100644 +--- a/ipatests/test_xmlrpc/test_automember_plugin.py ++++ b/ipatests/test_xmlrpc/test_automember_plugin.py +@@ -715,3 +715,51 @@ class TestMultipleAutomemberConditions(XMLRPC_test): + + defaultgroup1.ensure_missing() + defaulthostgroup1.ensure_missing() ++ ++ ++@pytest.mark.tier1 ++class TestAutomemberFindOrphans(XMLRPC_test): ++ def test_create_deps_for_find_orphans(self, hostgroup1, host1, ++ automember_hostgroup): ++ """ Create host, hostgroup, and automember tracker for this class ++ of tests. """ ++ ++ # Create hostgroup1 and automember rule with condition ++ hostgroup1.ensure_exists() ++ host1.ensure_exists() ++ ++ # Manually create automember rule and condition, racker will try to ++ # remove the automember rule in the end, which is failing as the rule ++ # is already removed ++ api.Command['automember_add'](hostgroup1.cn, type=u'hostgroup') ++ api.Command['automember_add_condition']( ++ hostgroup1.cn, ++ key=u'fqdn', type=u'hostgroup', ++ automemberinclusiveregex=[hostgroup_include_regex] ++ ) ++ ++ hostgroup1.retrieve() ++ ++ def test_find_orphan_automember_rules(self, hostgroup1): ++ """ Remove hostgroup1, find and remove obsolete automember rules. """ ++ # Remove hostgroup1 ++ ++ hostgroup1.ensure_missing() ++ ++ # Find obsolete automember rules ++ result = api.Command['automember_find_orphans'](type=u'hostgroup') ++ assert result['count'] == 1 ++ ++ # Find and remove obsolete automember rules ++ result = api.Command['automember_find_orphans'](type=u'hostgroup', ++ remove=True) ++ assert result['count'] == 1 ++ ++ # Find obsolete automember rules ++ result = api.Command['automember_find_orphans'](type=u'hostgroup') ++ assert result['count'] == 0 ++ ++ # Final cleanup of automember rule if it still exists ++ with raises_exact(errors.NotFound( ++ reason=u'%s: Automember rule not found' % hostgroup1.cn)): ++ api.Command['automember_del'](hostgroup1.cn, type=u'hostgroup') + diff --git a/SOURCES/0005-net-groupmap-force-using-empty-config.patch b/SOURCES/0005-net-groupmap-force-using-empty-config.patch new file mode 100644 index 0000000..2d07145 --- /dev/null +++ b/SOURCES/0005-net-groupmap-force-using-empty-config.patch @@ -0,0 +1,55 @@ +From 7f8858f8632d77497765bab79922f1762ce46d50 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 16 Oct 2018 17:54:09 +0300 +Subject: [PATCH] net groupmap: force using empty config when mapping Guests + +When we define a group mapping for BUILTIN\Guests to 'nobody' group in +we run 'net groupmap add ...' with a default /etc/samba/smb.conf which +is now configured to use ipasam passdb module. We authenticate to LDAP +with GSSAPI in ipasam passdb module initialization. + +If GSSAPI authentication failed (KDC is offline, for example, during +server upgrade), 'net groupmap add' crashes after ~10 attempts to +re-authenticate. This is intended behavior in smbd/winbindd as they +cannot work anymore. However, for the command line tools there are +plenty of operations where passdb module is not needed. + +Additionally, GSSAPI authentication uses the default ccache in the +environment and a key from /etc/samba/samba.keytab keytab. This means +that if you'd run 'net *' as root, it will replace whatever Kerberos +tickets you have with a TGT for cifs/`hostname` and a service ticket to +ldap/`hostname` of IPA master. + +Apply a simple solution to avoid using /etc/samba/smb.conf when we +set up the group mapping by specifying '-s /dev/null' in 'net groupmap' +call. + +For upgrade code this is enough as in +a678336b8b36cdbea2512e79c09e475fdc249569 we enforce use of empty +credentials cache during upgrade to prevent tripping on individual +ccaches from KEYRING: or KCM: cache collections. + +Related: https://pagure.io/freeipa/issue/7705 +(cherry picked from commit e48f5a4d64d95c4c5cb5f8ede39cae5c7c1e512c) +--- + ipaserver/install/adtrustinstance.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index da16748cf..3a751ccb2 100644 +--- a/ipaserver/install/adtrustinstance.py ++++ b/ipaserver/install/adtrustinstance.py +@@ -114,8 +114,8 @@ def make_netbios_name(s): + + def map_Guests_to_nobody(): + env = {'LC_ALL': 'C'} +- args = [paths.NET, 'groupmap', 'add', 'sid=S-1-5-32-546', +- 'unixgroup=nobody', 'type=builtin'] ++ args = [paths.NET, '-s', '/dev/null', 'groupmap', 'add', ++ 'sid=S-1-5-32-546', 'unixgroup=nobody', 'type=builtin'] + + logger.debug("Map BUILTIN\\Guests to a group 'nobody'") + ipautil.run(args, env=env, raiseonerr=False, capture_error=True) +-- +2.17.2 + diff --git a/SOURCES/0006-Keep-dogtags-client-db-in-external-ca-step-1.patch b/SOURCES/0006-Keep-dogtags-client-db-in-external-ca-step-1.patch new file mode 100644 index 0000000..4394a2b --- /dev/null +++ b/SOURCES/0006-Keep-dogtags-client-db-in-external-ca-step-1.patch @@ -0,0 +1,126 @@ +From 78bf80e55dd74fc0279cf6a76345865b0d5e5d32 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 26 Oct 2018 18:12:29 +0200 +Subject: [PATCH] Keep Dogtag's client db in external CA step 1 + +Don't remove /root/.dogtag/pki-tomcat when performing step 1 of external +CA installation process. Dogtag 10.6.7 changed behavior and no longer +re-creates the client database in step 2. + +Fixes: https://pagure.io/freeipa/issue/7742 +Signed-off-by: Christian Heimes +Reviewed-By: Rob Crittenden + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 59c0eadf1..61ccb6dff 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -483,7 +483,12 @@ class CAInstance(DogtagInstance): + try: + self.start_creation(runtime=runtime) + finally: +- self.clean_pkispawn_files() ++ if self.external == 1: ++ # Don't remove client DB in external CA step 1 ++ # https://pagure.io/freeipa/issue/7742 ++ logger.debug("Keep pkispawn files for step 2") ++ else: ++ self.clean_pkispawn_files() + + def __spawn_instance(self): + """ +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index e71bf2900..142a8c0d7 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -167,11 +167,13 @@ class DogtagInstance(service.Service): + + def clean_pkispawn_files(self): + if self.tmp_agent_db is not None: ++ logger.debug("Removing %s", self.tmp_agent_db) + shutil.rmtree(self.tmp_agent_db, ignore_errors=True) + +- shutil.rmtree('/root/.dogtag/pki-tomcat/{subsystem}/' +- .format(subsystem=self.subsystem.lower()), +- ignore_errors=True) ++ client_dir = os.path.join( ++ '/root/.dogtag/pki-tomcat/', self.subsystem.lower()) ++ logger.debug("Removing %s", client_dir) ++ shutil.rmtree(client_dir, ignore_errors=True) + + def restart_instance(self): + self.restart('pki-tomcat') + +From 6214fc51789dcfc70d4df18c0153877b92625ad2 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 26 Oct 2018 10:11:31 +0200 +Subject: [PATCH] Use tasks.install_master() in external_ca tests + +The install_master() function performs additional steps besides just +installing a server. It also sets up log collection and performs +additional tests. + +Signed-off-by: Christian Heimes +Reviewed-By: Rob Crittenden + +diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py +index 620ed28c9..9889636ba 100644 +--- a/ipatests/pytest_ipa/integration/tasks.py ++++ b/ipatests/pytest_ipa/integration/tasks.py +@@ -292,7 +292,7 @@ def set_default_ttl_for_ipa_dns_zone(host, 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): ++ external_ca=False, stdin_text=None, raiseonerr=True): + if domain_level is None: + domain_level = host.config.domain_level + check_domain_level(domain_level) +@@ -321,11 +321,14 @@ def install_master(host, setup_dns=True, setup_kra=False, setup_adtrust=False, + args.append('--setup-kra') + if setup_adtrust: + args.append('--setup-adtrust') ++ if external_ca: ++ args.append('--external-ca') + + args.extend(extra_args) + result = host.run_command(args, raiseonerr=raiseonerr, + stdin_text=stdin_text) +- if result.returncode == 0: ++ if result.returncode == 0 and not external_ca: ++ # external CA step 1 doesn't have DS and KDC fully configured, yet + enable_replication_debugging(host) + setup_sssd_debugging(host) + kinit_admin(host) +diff --git a/ipatests/test_integration/test_external_ca.py b/ipatests/test_integration/test_external_ca.py +index 33ba70f98..a8e0ea0bf 100644 +--- a/ipatests/test_integration/test_external_ca.py ++++ b/ipatests/test_integration/test_external_ca.py +@@ -70,24 +70,12 @@ def match_in_journal(host, string, since='today', services=('certmonger',)): + + + def install_server_external_ca_step1(host): +- """funtion for step 1 to install the ipa server with external ca""" +- +- args = ['ipa-server-install', '-U', +- '-a', host.config.admin_password, +- '-p', host.config.dirman_password, +- '--setup-dns', '--no-forwarders', +- '-n', host.domain.name, +- '-r', host.domain.realm, +- '--domain-level=%i' % host.config.domain_level, +- '--external-ca'] +- +- cmd = host.run_command(args) +- return cmd ++ """Step 1 to install the ipa server with external ca""" ++ return tasks.install_master(host, external_ca=True) + + + def install_server_external_ca_step2(host, ipa_ca_cert, root_ca_cert): +- """funtion for step 2 to install the ipa server with external ca""" +- ++ """Step 2 to install the ipa server with external ca""" + args = ['ipa-server-install', + '-a', host.config.admin_password, + '-p', host.config.dirman_password, diff --git a/SOURCES/0007-Replace-hard-coded-interpreter-with-sys.executable.patch b/SOURCES/0007-Replace-hard-coded-interpreter-with-sys.executable.patch new file mode 100644 index 0000000..541a4c2 --- /dev/null +++ b/SOURCES/0007-Replace-hard-coded-interpreter-with-sys.executable.patch @@ -0,0 +1,50 @@ +From 64045c5dbaf24340dea5cf0bdb629c29f70a4a9d Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 24 Oct 2018 16:08:16 +0200 +Subject: [PATCH] Replace hard-coded interpreter with sys.executable + +Instead of hard-coding python3, the smart card advise script now uses +the current executable path from sys.executable as interpreter. + +Fixes: https://pagure.io/freeipa/issue/7741 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy + +diff --git a/ipaserver/advise/plugins/smart_card_auth.py b/ipaserver/advise/plugins/smart_card_auth.py +index 2f2e7aec9..97e23303b 100644 +--- a/ipaserver/advise/plugins/smart_card_auth.py ++++ b/ipaserver/advise/plugins/smart_card_auth.py +@@ -4,6 +4,8 @@ + + from __future__ import absolute_import + ++import sys ++ + from ipalib.plugable import Registry + from ipaplatform import services + from ipaplatform.paths import paths +@@ -186,9 +188,9 @@ class config_server_for_smart_card_auth(common_smart_card_auth_config): + def record_httpd_ocsp_status(self): + self.log.comment('store the OCSP upgrade state') + self.log.command( +- "python3 -c 'from ipaserver.install import sysupgrade; " ++ "{} -c 'from ipaserver.install import sysupgrade; " + "sysupgrade.set_upgrade_state(\"httpd\", " +- "\"{}\", True)'".format(OCSP_ENABLED)) ++ "\"{}\", True)'".format(sys.executable, OCSP_ENABLED)) + + def check_and_enable_pkinit(self): + self.log.comment('check whether PKINIT is configured on the master') +@@ -310,10 +312,10 @@ class config_client_for_smart_card_auth(common_smart_card_auth_config): + def configure_pam_cert_auth(self): + self.log.comment('Set pam_cert_auth=True in /etc/sssd/sssd.conf') + self.log.command( +- "python3 -c 'from SSSDConfig import SSSDConfig; " ++ "{} -c 'from SSSDConfig import SSSDConfig; " + "c = SSSDConfig(); c.import_config(); " + "c.set(\"pam\", \"pam_cert_auth\", \"True\"); " +- "c.write()'") ++ "c.write()'".format(sys.executable)) + + def restart_sssd(self): + self.log.command('systemctl restart sssd.service') diff --git a/SOURCES/0008-Fix_misleading_errors_during_client_install_rollback_rhbz#1658283.patch b/SOURCES/0008-Fix_misleading_errors_during_client_install_rollback_rhbz#1658283.patch new file mode 100644 index 0000000..6a9dfdf --- /dev/null +++ b/SOURCES/0008-Fix_misleading_errors_during_client_install_rollback_rhbz#1658283.patch @@ -0,0 +1,213 @@ +From c64030a357401467d74e77d610d3bc268412220d Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 16 Oct 2018 13:58:00 -0400 +Subject: [PATCH] Remove the authselect profile warning if sssd was not + configured. + +On a plain uninstall there should not be a bunch of confusing +warning/error messages. + +Related to https://pagure.io/freeipa/issue/7729 + +Signed-off-by: Rob Crittenden +Reviewed-By: Christian Heimes +--- + ipatests/test_integration/test_authselect.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/ipatests/test_integration/test_authselect.py b/ipatests/test_integration/test_authselect.py +index 5eb3fdbf02..5ce56fa21e 100644 +--- a/ipatests/test_integration/test_authselect.py ++++ b/ipatests/test_integration/test_authselect.py +@@ -136,7 +136,6 @@ def test_uninstall_client_no_preconfigured_profile(self): + # by default + result = self._uninstall_client() + assert result.returncode == 0 +- assert self.msg_warn_uninstall in result.stderr_text + check_authselect_profile(self.client, default_profile) + + def test_install_client_preconfigured_profile(self): +From ec5e821f05cbc20517af6c9578e813f1963a9e8c Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Wed, 10 Oct 2018 14:07:33 -0400 +Subject: [PATCH] Fix misleading errors during client install rollback + +Some incorrect errors are possible if a client installation +fails and a configuration rollback is required. + +These include: + +1. Unconfigured automount client failed: CalledProcessError(Command +['/usr/sbin/ipa-client-automount', '--uninstall', '--debug'] +returned non-zero exit status 1: '') + +Caused by check_client_configuration() not returning the correct +return value (2). + +2. WARNING: Unable to revert to the pre-installation state ('authconfig' +tool has been deprecated in favor of 'authselect'). The default sssd +profile will be used instead. +The authconfig arguments would have been: authconfig --disableldap +--disablekrb5 --disablesssdauth --disablemkhomedir + +If installation fails before SSSD is configured there is no state +to roll back to. Detect this condition. + +3. An error occurred while removing SSSD's cache.Please remove the +cache manually by executing sssctl cache-remove -o. + +Again, if SSSD is not configured yet then there is no cache to +remove. Also correct the missing space after the period. + +https://pagure.io/freeipa/issue/7729 + +Signed-off-by: Rob Crittenden +Reviewed-By: Christian Heimes +--- + ipaclient/install/client.py | 18 ++++++----- + ipalib/util.py | 5 +++- + ipaplatform/redhat/authconfig.py | 2 +- + .../test_replica_promotion.py | 30 +++++++++++++++++++ + 4 files changed, 45 insertions(+), 10 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 0dcd1ec744..05255fe61b 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -3284,13 +3284,14 @@ def uninstall(options): + remove_file(paths.SSSD_MC_GROUP) + remove_file(paths.SSSD_MC_PASSWD) + +- try: +- run([paths.SSSCTL, "cache-remove", "-o", "--stop", "--start"]) +- except Exception: +- logger.info( +- "An error occurred while removing SSSD's cache." +- "Please remove the cache manually by executing " +- "sssctl cache-remove -o.") ++ if was_sssd_installed: ++ try: ++ run([paths.SSSCTL, "cache-remove", "-o", "--stop", "--start"]) ++ except Exception: ++ logger.info( ++ "An error occurred while removing SSSD's cache." ++ "Please remove the cache manually by executing " ++ "sssctl cache-remove -o.") + + if ipa_domain: + sssd_domain_ldb = "cache_" + ipa_domain + ".ldb" +@@ -3354,7 +3355,8 @@ def uninstall(options): + + # SSSD was not installed before our installation, and no other domains + # than IPA are configured in sssd.conf - make sure config file is removed +- elif not was_sssd_installed and not was_sssd_configured: ++ elif not was_sssd_installed and not was_sssd_configured \ ++ and os.path.exists(paths.SSSD_CONF): + try: + os.rename(paths.SSSD_CONF, paths.SSSD_CONF_DELETED) + except OSError: +diff --git a/ipalib/util.py b/ipalib/util.py +index 3e8fab49d6..68857baec7 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -1125,11 +1125,14 @@ def ensure_krbcanonicalname_set(ldap, entry_attrs): + def check_client_configuration(): + """ + Check if IPA client is configured on the system. ++ ++ Hardcode return code to avoid recursive imports + """ + if (not os.path.isfile(paths.IPA_DEFAULT_CONF) or + not os.path.isdir(paths.IPA_CLIENT_SYSRESTORE) or + not os.listdir(paths.IPA_CLIENT_SYSRESTORE)): +- raise ScriptError('IPA client is not configured on this system') ++ raise ScriptError('IPA client is not configured on this system', ++ 2) # CLIENT_NOT_CONFIGURED + + + def check_principal_realm_in_trust_namespace(api_instance, *keys): +diff --git a/ipaplatform/redhat/authconfig.py b/ipaplatform/redhat/authconfig.py +index ab3775e9e9..e456d9ec6e 100644 +--- a/ipaplatform/redhat/authconfig.py ++++ b/ipaplatform/redhat/authconfig.py +@@ -141,7 +141,7 @@ def configure(self, sssd, mkhomedir, statestore, sudo=True): + def unconfigure( + self, fstore, statestore, was_sssd_installed, was_sssd_configured + ): +- if not statestore.has_state('authselect'): ++ if not statestore.has_state('authselect') and was_sssd_installed: + logger.warning( + "WARNING: Unable to revert to the pre-installation state " + "('authconfig' tool has been deprecated in favor of " +diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py +index 265cbfb139..7803c34dcc 100644 +--- a/ipatests/test_integration/test_replica_promotion.py ++++ b/ipatests/test_integration/test_replica_promotion.py +@@ -207,6 +207,36 @@ def test_upcase_client_domain(self): + assert(result1.returncode == 0), ( + 'Failed to promote the client installed with the upcase domain name') + ++ def test_client_rollback(self): ++ """Test that bogus error msgs are not in output on rollback. ++ ++ FIXME: including in this suite to avoid setting up a ++ master just to test a client install failure. If ++ a pure client install suite is added this can be ++ moved. ++ ++ Ticket https://pagure.io/freeipa/issue/7729 ++ """ ++ client = self.replicas[0] ++ ++ # Cleanup previous run ++ client.run_command(['ipa-server-install', ++ '--uninstall', '-U'], raiseonerr=False) ++ ++ result = client.run_command(['ipa-client-install', '-U', ++ '--server', self.master.hostname, ++ '--domain', client.domain.name, ++ '-w', 'foo'], raiseonerr=False) ++ ++ assert(result.returncode == 1) ++ ++ assert("Unconfigured automount client failed" not in ++ result.stdout_text) ++ ++ assert("WARNING: Unable to revert" not in result.stdout_text) ++ ++ assert("An error occurred while removing SSSD" not in ++ result.stdout_text) + + class TestRenewalMaster(IntegrationTest): + +From db960e32f155412c34807e204add4858090d3e94 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 16 Oct 2018 14:07:25 -0400 +Subject: [PATCH] Collect the client and server uninstall logs in tests + +When running the integration tests capture the uninstallation +logs as well as the installation logs. + +Reviewed-By: Christian Heimes +--- + ipatests/pytest_ipa/integration/tasks.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py +index f0c61381b6..620ed28c96 100644 +--- a/ipatests/pytest_ipa/integration/tasks.py ++++ b/ipatests/pytest_ipa/integration/tasks.py +@@ -69,11 +69,12 @@ def setup_server_logs_collecting(host): + + # IPA install logs + host.collect_log(paths.IPASERVER_INSTALL_LOG) ++ host.collect_log(paths.IPASERVER_UNINSTALL_LOG) + host.collect_log(paths.IPACLIENT_INSTALL_LOG) ++ host.collect_log(paths.IPACLIENT_UNINSTALL_LOG) + host.collect_log(paths.IPAREPLICA_INSTALL_LOG) + host.collect_log(paths.IPAREPLICA_CONNCHECK_LOG) + host.collect_log(paths.IPAREPLICA_CA_INSTALL_LOG) +- host.collect_log(paths.IPACLIENT_INSTALL_LOG) + host.collect_log(paths.IPASERVER_KRA_INSTALL_LOG) + host.collect_log(paths.IPA_CUSTODIA_AUDIT_LOG) + diff --git a/SOURCES/0009-ipa-advise_update_url_of_cacerdir_rehash_tool_9cfd07e_rhbz#1658287.patch b/SOURCES/0009-ipa-advise_update_url_of_cacerdir_rehash_tool_9cfd07e_rhbz#1658287.patch new file mode 100644 index 0000000..40b5db5 --- /dev/null +++ b/SOURCES/0009-ipa-advise_update_url_of_cacerdir_rehash_tool_9cfd07e_rhbz#1658287.patch @@ -0,0 +1,55 @@ +From 9cfd07e87964f37465dd699a50444e6953291f59 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Oct 23 2018 14:48:53 +0000 +Subject: ipa-advise: update url of cacerdir_rehash tool + + +On legacy systems which don't have cacerdir_rehash tool (provided by authconfig) +the generated advise script downloads this tool from project page and uses it. + +After decommision of Fedorahosted and move of authconfig project to Pagure, +this url was not updated in FreeIPA project. + +This patch updates the url. + +https://pagure.io/freeipa/issue/7731 + +Signed-off-by: Petr Vobornik +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipaserver/advise/plugins/legacy_clients.py b/ipaserver/advise/plugins/legacy_clients.py +index 7916965..2a56922 100644 +--- a/ipaserver/advise/plugins/legacy_clients.py ++++ b/ipaserver/advise/plugins/legacy_clients.py +@@ -28,6 +28,9 @@ from ipapython.ipautil import template_file + + register = Registry() + ++CACERTDIR_REHASH_URL = ('https://pagure.io/authconfig/raw/master/f/' ++ 'cacertdir_rehash') ++ + + class config_base_legacy_client(Advice): + def get_uri_and_base(self): +@@ -50,8 +53,6 @@ class config_base_legacy_client(Advice): + 'location. If this value is different on your system ' + 'the script needs to be modified accordingly.\n') + +- cacertdir_rehash = ('https://fedorahosted.org/authconfig/browser/' +- 'cacertdir_rehash?format=txt') + self.log.comment('Download the CA certificate of the IPA server') + self.log.command('mkdir -p -m 755 /etc/openldap/cacerts') + self.log.command('curl http://%s/ipa/config/ca.crt -o ' +@@ -60,7 +61,8 @@ class config_base_legacy_client(Advice): + self.log.comment('Generate hashes for the openldap library') + self.log.command('command -v cacertdir_rehash') + self.log.command('if [ $? -ne 0 ] ; then') +- self.log.command(' curl "%s" -o cacertdir_rehash ;' % cacertdir_rehash) ++ self.log.command(' curl "%s" -o cacertdir_rehash ;' % ++ CACERTDIR_REHASH_URL) + self.log.command(' chmod 755 ./cacertdir_rehash ;') + self.log.command(' ./cacertdir_rehash /etc/openldap/cacerts/ ;') + self.log.command('else') + diff --git a/SOURCES/0010-Handle_NTP_configuration_in_replica_server_installation_f3e3da5_rhbz#1651679.patch b/SOURCES/0010-Handle_NTP_configuration_in_replica_server_installation_f3e3da5_rhbz#1651679.patch new file mode 100644 index 0000000..b5d4f50 --- /dev/null +++ b/SOURCES/0010-Handle_NTP_configuration_in_replica_server_installation_f3e3da5_rhbz#1651679.patch @@ -0,0 +1,69 @@ +From f3e3da509329881c4ba770d1f9418ad180ee98ae Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Oct 19 2018 17:35:05 +0000 +Subject: Handle NTP configuration in a replica server installation + + +There were two separate issues: + +1. If not enrolling on a pre-configured client then the ntp-server and + ntp-pool options are not being passed down to the client installer + invocation. +2. If the client is already enrolled then the ntp options are ignored + altogether. + +In the first case simply pass down the options to the client +installer invocation. + +If the client is pre-enrolled and NTP options are provided then +raise an exception. + +https://pagure.io/freeipa/issue/7723 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud + +--- + +diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 +index 7f6ca57..c63107d 100644 +--- a/install/tools/man/ipa-replica-install.1 ++++ b/install/tools/man/ipa-replica-install.1 +@@ -14,7 +14,7 @@ Domain level 0 is not supported anymore. + + To create a replica, the machine only needs to be enrolled in the FreeIPA domain first. This process of turning the IPA client into a replica is also referred to as replica promotion. + +-If you're starting with an existing IPA client, simply run ipa\-replica\-install to have it promoted into a replica. ++If you're starting with an existing IPA client, simply run ipa\-replica\-install to have it promoted into a replica. The NTP configuration cannot be updated during client promotion. + + To promote a blank machine into a replica, you have two options, you can either run ipa\-client\-install in a separate step, or pass the enrollment related options to the ipa\-replica\-install (see CLIENT ENROLLMENT OPTIONS). In the latter case, ipa\-replica\-install will join the machine to the IPA realm automatically and will proceed with the promotion step. + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index aaa1943..3022057 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -717,6 +717,11 @@ def ensure_enrolled(installer): + for ip in installer.ip_addresses: + # installer.ip_addresses is of type [CheckedIPAddress] + args.extend(("--ip-address", str(ip))) ++ if installer.ntp_servers: ++ for server in installer.ntp_servers: ++ args.extend(("--ntp-server", server)) ++ if installer.ntp_pool: ++ args.extend(("--ntp-pool", installer.ntp_pool)) + + try: + # Call client install script +@@ -774,6 +779,11 @@ def promote_check(installer): + "the --domain, --server, --realm, --hostname, --password " + "and --keytab options.") + ++ # The NTP configuration can not be touched on pre-installed client: ++ if options.no_ntp or options.ntp_servers or options.ntp_pool: ++ raise ScriptError( ++ "NTP configuration cannot be updated during promotion") ++ + sstore = sysrestore.StateFile(paths.SYSRESTORE) + + fstore = sysrestore.FileStore(paths.SYSRESTORE) + diff --git a/SOURCES/0011-Fix_defects_found_by_static_analysis_rhbz#1658182.patch b/SOURCES/0011-Fix_defects_found_by_static_analysis_rhbz#1658182.patch new file mode 100644 index 0000000..539a57c --- /dev/null +++ b/SOURCES/0011-Fix_defects_found_by_static_analysis_rhbz#1658182.patch @@ -0,0 +1,449 @@ +From 705e280eafb13b1b55fc0b91001e4721ce79fbdf Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Mon, 22 Oct 2018 13:57:11 +0200 +Subject: [PATCH] Fix ressource leak in client/config.c get_config_entry + +The leak happens due to using strndup to create a temporary string without +freeing it afterwards. + +See: https://pagure.io/freeipa/issue/7738 +Signed-off-by: Thomas Woerner +Reviewed-By: Christian Heimes +--- + client/config.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/client/config.c b/client/config.c +index ecc126ff47..a09564b702 100644 +--- a/client/config.c ++++ b/client/config.c +@@ -123,17 +123,18 @@ get_config_entry(char * in_data, const char *section, const char *key) + line++; + p = strchr(line, ']'); + if (p) { +- tmp = strndup(line, p - line); + if (in_section) { + /* We exited the matching section without a match */ + free(data); + return NULL; + } ++ tmp = strndup(line, p - line); + if (strcmp(section, tmp) == 0) { + free(tmp); + in_section = 1; + continue; + } ++ free(tmp); + } + } /* [ */ + +From ebb14ed6f57c5504dc2f44339274b108483efd16 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Mon, 22 Oct 2018 15:18:23 +0200 +Subject: [PATCH] Fix ressource leak in + daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c ipa_cldap_netlogon + +The leak happens due to using strndup in a for loop to create a temporary +string without freeing it in all cases. + +See: https://pagure.io/freeipa/issue/7738 +Signed-off-by: Thomas Woerner +Reviewed-By: Christian Heimes +--- + daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c +index 5863f667ea..460f96cd59 100644 +--- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c ++++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c +@@ -260,6 +260,10 @@ int ipa_cldap_netlogon(struct ipa_cldap_ctx *ctx, + if (req->kvps.pairs[i].value.bv_val[len-1] == '.') { + len--; + } ++ if (domain != NULL) { ++ free(domain); ++ domain = NULL; ++ } + domain = strndup(req->kvps.pairs[i].value.bv_val, len); + if (!domain) { + ret = ENOMEM; +From 305150416429b85d46ad4162bac492db303cf9cf Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 24 Oct 2018 10:12:39 +0200 +Subject: [PATCH] Fix ipadb_multires resource handling + +* ipadb_get_pwd_policy() initializes struct ipadb_multires *res to NULL. +* ipadb_multires_free() supports NULL as no-op. +* ipadb_multibase_search() consistently frees and NULLs + struct ipadb_multires **res on error. + +See: https://pagure.io/freeipa/issue/7738 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb_common.c | 13 +++++++++---- + daemons/ipa-kdb/ipa_kdb_pwdpolicy.c | 2 +- + 2 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_common.c b/daemons/ipa-kdb/ipa_kdb_common.c +index 5995efe6b1..e2592cea3f 100644 +--- a/daemons/ipa-kdb/ipa_kdb_common.c ++++ b/daemons/ipa-kdb/ipa_kdb_common.c +@@ -634,10 +634,12 @@ krb5_error_code ipadb_multires_init(LDAP *lcontext, struct ipadb_multires **r) + + void ipadb_multires_free(struct ipadb_multires *r) + { +- for (int i = 0; i < r->count; i++) { +- ldap_msgfree(r->res[i]); ++ if (r != NULL) { ++ for (int i = 0; i < r->count; i++) { ++ ldap_msgfree(r->res[i]); ++ } ++ free(r); + } +- free(r); + } + + LDAPMessage *ipadb_multires_next_entry(struct ipadb_multires *r) +@@ -670,8 +672,11 @@ krb5_error_code ipadb_multibase_search(struct ipadb_context *ipactx, + if (ret != 0) return ret; + + ret = ipadb_check_connection(ipactx); +- if (ret != 0) ++ if (ret != 0) { ++ ipadb_multires_free(*res); ++ *res = NULL; + return ipadb_simple_ldap_to_kerr(ret); ++ } + + for (int b = 0; basedns[b]; b++) { + LDAPMessage *r; +diff --git a/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c b/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c +index 1ec584612b..10f128700b 100644 +--- a/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c ++++ b/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c +@@ -141,7 +141,7 @@ krb5_error_code ipadb_get_pwd_policy(krb5_context kcontext, char *name, + char *esc_name = NULL; + char *src_filter = NULL; + krb5_error_code kerr; +- struct ipadb_multires *res; ++ struct ipadb_multires *res = NULL; + LDAPMessage *lentry; + osa_policy_ent_t pentry = NULL; + uint32_t result; +From 4ca3120b9a09ad48866446af29b38ca7c005b0d0 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 24 Oct 2018 10:19:14 +0200 +Subject: [PATCH] Don't abuse strncpy() length limitation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On two occasions C code abused strncpy()'s length limitation to copy a +string of known length without the trailing NULL byte. Recent GCC is +raising the compiler warning: + + warning: ‘strncpy’ output truncated before terminating nul copying as + many bytes from a string as its length [-Wstringop-truncation] + +Use memcpy() instead if strncpy() to copy data of known size. + +See: https://pagure.io/freeipa/issue/7738 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb.c | 2 +- + daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index 00c732624b..20967316ed 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -110,7 +110,7 @@ static char *ipadb_realm_to_ldapi_uri(char *realm) + /* copy path and escape '/' to '%2f' */ + for (q = LDAPIDIR; *q; q++) { + if (*q == '/') { +- strncpy(p, "%2f", 3); ++ memcpy(p, "%2f", 3); + p += 3; + } else { + *p = *q; +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +index db7183bf2b..61b46904ab 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +@@ -1003,7 +1003,7 @@ int ipapwd_set_extradata(const char *dn, + xdata[5] = (unixtime & 0xff000000) >> 24; + + /* append the principal name */ +- strncpy(&xdata[6], principal, p_len); ++ memcpy(&xdata[6], principal, p_len); + + xdata[xd_len -1] = 0; + +From a06fb8d0f7b7c6aba942186b93d87823398f5337 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 1 Nov 2018 11:41:29 +0100 +Subject: [PATCH] has_krbprincipalkey: avoid double free + +Set keys to NULL after free rder to avoid potential double free. + +See: https://pagure.io/freeipa/issue/7738 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +index 209d596255..3c3c7e8845 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +@@ -176,7 +176,11 @@ static bool has_krbprincipalkey(Slapi_Entry *entry) { + + if (rc || (num_keys <= 0)) { + /* this one is not valid, ignore it */ +- if (keys) ipa_krb5_free_key_data(keys, num_keys); ++ if (keys) { ++ ipa_krb5_free_key_data(keys, num_keys); ++ keys = NULL; ++ num_keys = 0; ++ } + } else { + /* It exists at least this one that is valid, no need to continue */ + if (keys) ipa_krb5_free_key_data(keys, num_keys); +From 2884ab69babfd7d40f951ba814234ce4763b0cd8 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 1 Nov 2018 11:41:41 +0100 +Subject: [PATCH] ipadb_mspac_get_trusted_domains: NULL ptr deref + +Fix potential NULL pointer deref in ipadb_mspac_get_trusted_domains(). +In theory, dn could be empty and rdn NULL. The man page for ldap_str2dn() +does not guarantee that it returns a non-empty result. + +See: https://pagure.io/freeipa/issue/7738 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 11e036986a..329a5c1158 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -2586,6 +2586,12 @@ krb5_error_code ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx) + } + + /* We should have a single AVA in the domain RDN */ ++ if (rdn == NULL) { ++ ldap_dnfree(dn); ++ ret = EINVAL; ++ goto done; ++ } ++ + t[n].parent_name = strndup(rdn[0]->la_value.bv_val, rdn[0]->la_value.bv_len); + + ldap_dnfree(dn); +From 28b89df5ed8a9a060227433e8eeebf7eea844bb9 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 1 Nov 2018 11:41:47 +0100 +Subject: [PATCH] ipapwd_pre_mod: NULL ptr deref + +In ipapwd_pre_mod, check userpw for NULL before dereferencing its first +element. + +See: https://pagure.io/freeipa/issue/7738 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +index 3c3c7e8845..9aef2f7d7d 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +@@ -766,7 +766,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) + /* Check this is a clear text password, or refuse operation (only if we need + * to comput other hashes */ + if (! unhashedpw && (gen_krb_keys || is_smb || is_ipant)) { +- if ('{' == userpw[0]) { ++ if ((userpw != NULL) && ('{' == userpw[0])) { + if (0 == strncasecmp(userpw, "{CLEAR}", strlen("{CLEAR}"))) { + unhashedpw = slapi_ch_strdup(&userpw[strlen("{CLEAR}")]); + if (NULL == unhashedpw) { +From 5abe3d9feff3c0e66a43fa3799611521f83ee893 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 7 Nov 2018 11:57:53 +0200 +Subject: [PATCH] ipaserver.install.adtrust: fix CID 323644 + +Fix Coverity finding CID 323644: logically dead code path + +The code to determine whether NetBIOS name was already set or need to be +set after deriving it from a domain or asking a user for an interactive +input, was refactored at some point to avoid retrieving the whole LDAP +entry. Instead, it was provided with the actual NetBIOS name retrieved. + +As result, a part of the code got neglected and was never executed. + +Fix this code and provide a test that tries to test predefined, +interactively provided and automatically derived NetBIOS name depending +on how the installer is being run. + +We mock up the actual execution so that no access to LDAP or Samba is +needed. + +Backport to ipa-4-7 takes into account Python 2.7 differences: + - uses mock instead of unittest.mock if the latter is not available + - derives ApiMockup from object + +Fixes: https://pagure.io/freeipa/issue/7753 +Reviewed-By: Christian Heimes +(cherry picked from commit 82af034023b03ae64f005c8160b9e961e7b9fd55) + +Reviewed-By: Christian Heimes +--- + ipaserver/install/adtrust.py | 3 +- + .../test_ipaserver/test_adtrust_mockup.py | 58 +++++++++++++++++++ + 2 files changed, 59 insertions(+), 2 deletions(-) + create mode 100644 ipatests/test_ipaserver/test_adtrust_mockup.py + +diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py +index e9ae3fa3ed..75194eed8f 100644 +--- a/ipaserver/install/adtrust.py ++++ b/ipaserver/install/adtrust.py +@@ -95,7 +95,6 @@ def set_and_check_netbios_name(netbios_name, unattended, api): + cur_netbios_name = None + gen_netbios_name = None + reset_netbios_name = False +- entry = None + + if api.Backend.ldap2.isconnected(): + cur_netbios_name = retrieve_netbios_name(api) +@@ -133,7 +132,7 @@ def set_and_check_netbios_name(netbios_name, unattended, api): + gen_netbios_name = adtrustinstance.make_netbios_name( + api.env.domain) + +- if entry is not None: ++ if gen_netbios_name is not None: + # Fix existing trust configuration + print("Trust is configured but no NetBIOS domain name found, " + "setting it now.") +diff --git a/ipatests/test_ipaserver/test_adtrust_mockup.py b/ipatests/test_ipaserver/test_adtrust_mockup.py +new file mode 100644 +index 0000000000..614a06f8c8 +--- /dev/null ++++ b/ipatests/test_ipaserver/test_adtrust_mockup.py +@@ -0,0 +1,58 @@ ++# Copyright (C) 2018 FreeIPA Project Contributors - see LICENSE file ++ ++from __future__ import print_function ++import ipaserver.install.adtrust as adtr ++from ipaserver.install.adtrust import set_and_check_netbios_name ++from collections import namedtuple ++from unittest import TestCase ++try: ++ from unittest import mock ++except ImportError: ++ import mock ++from io import StringIO ++ ++ ++class ApiMockup(object): ++ Backend = namedtuple('Backend', 'ldap2') ++ Calls = namedtuple('Callbacks', 'retrieve_netbios_name') ++ env = namedtuple('Environment', 'domain') ++ ++ ++class TestNetbiosName(TestCase): ++ @classmethod ++ def setUpClass(cls): ++ api = ApiMockup() ++ ldap2 = namedtuple('LDAP', 'isconnected') ++ ldap2.isconnected = mock.MagicMock(return_value=True) ++ api.Backend.ldap2 = ldap2 ++ api.Calls.retrieve_netbios_name = adtr.retrieve_netbios_name ++ adtr.retrieve_netbios_name = mock.MagicMock(return_value=None) ++ cls.api = api ++ ++ @classmethod ++ def tearDownClass(cls): ++ adtr.retrieve_netbios_name = cls.api.Calls.retrieve_netbios_name ++ ++ def test_NetbiosName(self): ++ """ ++ Test set_and_check_netbios_name() using permutation of two inputs: ++ - predefined and not defined NetBIOS name ++ - unattended and interactive run ++ As result, the function has to return expected NetBIOS name in ++ all cases. For interactive run we override input to force what ++ we expect. ++ """ ++ self.api.env.domain = 'example.com' ++ expected_nname = 'EXAMPLE' ++ # NetBIOS name, unattended, should set the name? ++ tests = ((expected_nname, True, False), ++ (None, True, True), ++ (None, False, True), ++ (expected_nname, False, False)) ++ with mock.patch('sys.stdin', new_callable=StringIO) as stdin: ++ stdin.write(expected_nname + '\r') ++ for test in tests: ++ nname, setname = set_and_check_netbios_name( ++ test[0], test[1], self.api) ++ assert expected_nname == nname ++ assert setname == test[2] +From 48a6048be2a3c6cf496a67a2732b8aaee91af620 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 8 Nov 2018 10:42:43 +0100 +Subject: [PATCH] Copy-paste error in permssions plugin, CID 323649 + +Address a bug in the code block for attributeLevelRights for old clients. +The backward compatibility code for deprecated options was not triggered, +because the new name was checked against wrong dict. + +Coverity Scan issue 323649, Copy-paste error + + The copied code will not have its intended effect. + In postprocess_result: A copied piece of code is inconsistent with the + original (CWE-398) + +See: Fixes: https://pagure.io/freeipa/issue/7753 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + ipaserver/plugins/permission.py | 2 +- + ipatests/test_xmlrpc/test_old_permission_plugin.py | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/plugins/permission.py b/ipaserver/plugins/permission.py +index 2127d8234e..8ffe01bd88 100644 +--- a/ipaserver/plugins/permission.py ++++ b/ipaserver/plugins/permission.py +@@ -486,7 +486,7 @@ def postprocess_result(self, entry, options): + + if old_client: + for old_name, new_name in _DEPRECATED_OPTION_ALIASES.items(): +- if new_name in entry: ++ if new_name in rights: + rights[old_name] = rights[new_name] + del rights[new_name] + +diff --git a/ipatests/test_xmlrpc/test_old_permission_plugin.py b/ipatests/test_xmlrpc/test_old_permission_plugin.py +index 6d1117b6b3..600e449421 100644 +--- a/ipatests/test_xmlrpc/test_old_permission_plugin.py ++++ b/ipatests/test_xmlrpc/test_old_permission_plugin.py +@@ -73,8 +73,8 @@ + 'ipapermbindruletype': u'rscwo', + 'ipapermdefaultattr': u'rscwo', + 'ipapermexcludedattr': u'rscwo', +- 'ipapermlocation': u'rscwo', +- 'ipapermright': u'rscwo', ++ 'subtree': u'rscwo', # old ++ 'permissions': u'rscwo', # old + 'ipapermtarget': u'rscwo', + 'ipapermtargetfilter': u'rscwo', + 'ipapermtargetto': u'rscwo', diff --git a/SOURCES/0012-ipa-replica-install_--setup-adtrust_check_for_package_ipa-server-trust-ad_rhbz#1658294.patch b/SOURCES/0012-ipa-replica-install_--setup-adtrust_check_for_package_ipa-server-trust-ad_rhbz#1658294.patch new file mode 100644 index 0000000..c5bc02d --- /dev/null +++ b/SOURCES/0012-ipa-replica-install_--setup-adtrust_check_for_package_ipa-server-trust-ad_rhbz#1658294.patch @@ -0,0 +1,65 @@ +From be968ea01adf1721b0afd7393872a8d311d89d0c Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Oct 24 2018 14:21:47 +0000 +Subject: ipa-replica-install --setup-adtrust: check for package ipa-server-trust-ad + + +When adding the option --setup-adtrust to ipa-replica-install, +we need to check that the package freeipa-server-trust-ad is +installed. +To avoid relying on OS-specific commands like yum, the check is instead +ensuring that the file /usr/share/ipa/smb.conf.empty is present +(this file is delivered by the package). +When the check is unsuccessful, ipa-replica-install exits with an error +message. + +Fixes: https://pagure.io/freeipa/issue/7602 +Reviewed-By: Alexander Bokovoy + +--- + +diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py +index be832fe..c67b991 100644 +--- a/ipaplatform/base/constants.py ++++ b/ipaplatform/base/constants.py +@@ -15,6 +15,7 @@ class BaseConstantsNamespace(object): + HTTPD_USER = "apache" + HTTPD_GROUP = "apache" + GSSPROXY_USER = "root" ++ IPA_ADTRUST_PACKAGE_NAME = "freeipa-server-trust-ad" + IPA_DNS_PACKAGE_NAME = "freeipa-server-dns" + KDCPROXY_USER = "kdcproxy" + NAMED_USER = "named" +diff --git a/ipaplatform/rhel/constants.py b/ipaplatform/rhel/constants.py +index 945f3dc..72335ac 100644 +--- a/ipaplatform/rhel/constants.py ++++ b/ipaplatform/rhel/constants.py +@@ -13,6 +13,7 @@ from ipaplatform.redhat.constants import RedHatConstantsNamespace + + + class RHELConstantsNamespace(RedHatConstantsNamespace): ++ IPA_ADTRUST_PACKAGE_NAME = "ipa-server-trust-ad" + IPA_DNS_PACKAGE_NAME = "ipa-server-dns" + + constants = RHELConstantsNamespace() +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index 3a751cc..67317ee 100644 +--- a/ipaserver/install/adtrustinstance.py ++++ b/ipaserver/install/adtrustinstance.py +@@ -72,6 +72,15 @@ def check_inst(): + "start the installation again") + return False + ++ # Check that ipa-server-trust-ad package is installed, ++ # by looking for the file /usr/share/ipa/smb.conf.empty ++ if not os.path.exists(os.path.join(paths.USR_SHARE_IPA_DIR, ++ "smb.conf.empty")): ++ print("AD Trust requires the '%s' package" % ++ constants.IPA_ADTRUST_PACKAGE_NAME) ++ print("Please install the package and start the installation again") ++ return False ++ + #TODO: Add check for needed samba4 libraries + + return True + diff --git a/SOURCES/0013-ipaldap_invalid_modlist_when_attribute_encoding_can_vary_rhbz#1658302.patch b/SOURCES/0013-ipaldap_invalid_modlist_when_attribute_encoding_can_vary_rhbz#1658302.patch new file mode 100644 index 0000000..270cbdf --- /dev/null +++ b/SOURCES/0013-ipaldap_invalid_modlist_when_attribute_encoding_can_vary_rhbz#1658302.patch @@ -0,0 +1,72 @@ +From 9e7e9c1014c10f838b341a45436aba0840ad5b07 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Nov 07 2018 13:51:59 +0000 +Subject: ipaldap: avoid invalid modlist when attribute encoding differs + + +ipaldap does not take into account the possibility of the attribute +encoding returned by python-ldap differing from the attribute +encoding produced by FreeIPA. In particular this can occur with DNs +with special characters that require escaping. For example, +python-ldap (or the underlying LDAP library) escapes special +characters using hex encoding: + + CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\2C Inc.,L=Brisbane,C=AU + +Whereas FreeIPA, when encoding the DN, escapes the character +directly: + + CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\, Inc.,L=Brisbane,C=AU + +Therefore it is possible to generate an invalid modlist. For +example, during external CA certificate renewal, if the issuer DN +includes a comma in one of the attribute values (as above), an +invalid modlist will be generated: + + [ (ldap.MOD_ADD, 'ipacaissuerdn', + [b'CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\, Inc.,L=Brisbane,C=AU']) + , (ldap.MOD_DELETE, 'ipacaissuerdn', + [b'CN=Test Sub-CA 201604041620,OU=ftweedal,O=Red Hat\2C Inc.,L=Brisbane,C=AU']) + ] + +Although encoded differently, these are the same value. If this +modification is applied to the object, attributeOrValueExists (error +20) occurs. + +To avoid the issue, put deletes before adds in the modlist. If a +value is present (with different encodings) as both an addition and +a deletion, it must be because the original object contained the +value with a different encoding. Therefore it is safe to delete it, +then add it back. + +Note that the modlist is not optimal. In the simplest case (like +above example), there should be no modification to perform. It is +considerably more complex (and more computation) to implement this +because the raw attribute values must be decoded before comparison. + +Fixes: https://pagure.io/freeipa/issue/7750 +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py +index fbc824e..cf1e60b 100644 +--- a/ipapython/ipaldap.py ++++ b/ipapython/ipaldap.py +@@ -565,10 +565,13 @@ class LDAPEntry(MutableMapping): + raise errors.OnlyOneValueAllowed(attr=name) + modlist.append((ldap.MOD_REPLACE, name, adds)) + else: +- if adds: +- modlist.append((ldap.MOD_ADD, name, adds)) ++ # dels before adds, in case the same value occurs in ++ # both due to encoding differences ++ # (https://pagure.io/freeipa/issue/7750) + if dels: + modlist.append((ldap.MOD_DELETE, name, dels)) ++ if adds: ++ modlist.append((ldap.MOD_ADD, name, adds)) + + # Usually the modlist order does not matter. + # However, for schema updates, we want 'attributetypes' before + diff --git a/SOURCES/0014-Allow_ipaapi_and_Apache_user_to_access_SSSD_IFP_rhbz#1639910.patch b/SOURCES/0014-Allow_ipaapi_and_Apache_user_to_access_SSSD_IFP_rhbz#1639910.patch new file mode 100644 index 0000000..9a6f2b7 --- /dev/null +++ b/SOURCES/0014-Allow_ipaapi_and_Apache_user_to_access_SSSD_IFP_rhbz#1639910.patch @@ -0,0 +1,816 @@ +From 785c496dceb76a8f628249ce598e0540b1dfec6e Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Tue, 6 Nov 2018 13:57:14 +0100 +Subject: [PATCH] Allow ipaapi user to access SSSD's info pipe + +For smart card authentication, ipaapi must be able to access to sss-ifp. +During installation and upgrade, the ipaapi user is now added to +[ifp]allowed_uids. + +The commit also fixes two related issues: + +* The server upgrade code now enables ifp service in sssd.conf. The + existing code modified sssd.conf but never wrote the changes to disk. +* sssd_enable_service() no longer fails after it has detected an + unrecognized service. + +Fixes: https://pagure.io/freeipa/issue/7751 +Signed-off-by: Christian Heimes +Reviewed-By: Rob Crittenden +--- + ipaclient/install/client.py | 41 ++++++++++++++++++---- + ipaserver/install/server/upgrade.py | 27 +++++++++----- + ipatests/test_integration/test_commands.py | 31 ++++++++++++++++ + 3 files changed, 83 insertions(+), 16 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 05255fe61b..f9b003ef57 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -35,6 +35,7 @@ + # pylint: enable=import-error + + from ipalib import api, errors, x509 ++from ipalib.constants import IPAAPI_USER + from ipalib.install import certmonger, certstore, service, sysrestore + from ipalib.install import hostname as hostname_ + from ipalib.install.kinit import kinit_keytab, kinit_password +@@ -914,7 +915,7 @@ def configure_sssd_conf( + domain = sssdconfig.new_domain(cli_domain) + + if options.on_master: +- sssd_enable_service(sssdconfig, 'ifp') ++ sssd_enable_ifp(sssdconfig) + + if ( + (options.conf_ssh and os.path.isfile(paths.SSH_CONFIG)) or +@@ -1018,21 +1019,47 @@ def configure_sssd_conf( + return 0 + + +-def sssd_enable_service(sssdconfig, service): ++def sssd_enable_service(sssdconfig, name): + try: +- sssdconfig.new_service(service) ++ sssdconfig.new_service(name) + except SSSDConfig.ServiceAlreadyExists: + pass + except SSSDConfig.ServiceNotRecognizedError: + logger.error( +- "Unable to activate the %s service in SSSD config.", service) ++ "Unable to activate the '%s' service in SSSD config.", name) + logger.info( + "Please make sure you have SSSD built with %s support " +- "installed.", service) ++ "installed.", name) + logger.info( +- "Configure %s support manually in /etc/sssd/sssd.conf.", service) ++ "Configure %s support manually in /etc/sssd/sssd.conf.", name) ++ return None + +- sssdconfig.activate_service(service) ++ sssdconfig.activate_service(name) ++ return sssdconfig.get_service(name) ++ ++ ++def sssd_enable_ifp(sssdconfig): ++ """Enable and configure libsss_simpleifp plugin ++ """ ++ service = sssd_enable_service(sssdconfig, 'ifp') ++ if service is None: ++ # unrecognized service ++ return ++ ++ try: ++ uids = service.get_option('allowed_uids') ++ except SSSDConfig.NoOptionError: ++ uids = set() ++ else: ++ uids = {s.strip() for s in uids.split(',') if s.strip()} ++ # SSSD supports numeric and string UIDs ++ # ensure that root is allowed to access IFP, might be 0 or root ++ if uids.isdisjoint({'0', 'root'}): ++ uids.add('root') ++ # allow IPA API to access IFP ++ uids.add(IPAAPI_USER) ++ service.set_option('allowed_uids', ', '.join(sorted(uids))) ++ sssdconfig.save_service(service) + + + def change_ssh_config(filename, changes, sections): +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 96c95b7a07..698afd347e 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -23,7 +23,7 @@ + import ipalib.util + import ipalib.errors + from ipaclient.install import timeconf +-from ipaclient.install.client import sssd_enable_service ++from ipaclient.install.client import sssd_enable_ifp + from ipaplatform import services + from ipaplatform.tasks import tasks + from ipapython import ipautil, version +@@ -1408,6 +1408,22 @@ def set_sssd_domain_option(option, value): + sssdconfig.write(paths.SSSD_CONF) + + ++def sssd_update(): ++ sssdconfig = SSSDConfig.SSSDConfig() ++ sssdconfig.import_config() ++ # upgrade domain ++ domain = sssdconfig.get_domain(str(api.env.domain)) ++ domain.set_option('ipa_server_mode', 'True') ++ domain.set_option('ipa_server', api.env.host) ++ sssdconfig.save_domain(domain) ++ # enable and configure IFP plugin ++ sssd_enable_ifp(sssdconfig) ++ # write config and restart service ++ sssdconfig.write(paths.SSSD_CONF) ++ sssd = services.service('sssd', api) ++ sssd.restart() ++ ++ + def remove_ds_ra_cert(subject_base): + logger.info('[Removing RA cert from DS NSS database]') + +@@ -2017,15 +2033,8 @@ def upgrade_configuration(): + cainstance.ensure_ipa_authority_entry() + + migrate_to_authselect() +- set_sssd_domain_option('ipa_server_mode', 'True') +- set_sssd_domain_option('ipa_server', api.env.host) + +- sssdconfig = SSSDConfig.SSSDConfig() +- sssdconfig.import_config() +- sssd_enable_service(sssdconfig, 'ifp') +- +- sssd = services.service('sssd', api) +- sssd.restart() ++ sssd_update() + + krb = krbinstance.KrbInstance(fstore) + krb.fqdn = fqdn +diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py +index 640eacfa06..1aa1bb3313 100644 +--- a/ipatests/test_integration/test_commands.py ++++ b/ipatests/test_integration/test_commands.py +@@ -20,6 +20,8 @@ + from cryptography.hazmat.backends import default_backend + from cryptography import x509 + ++from ipalib.constants import IPAAPI_USER ++ + from ipaplatform.paths import paths + + from ipatests.test_integration.base import IntegrationTest +@@ -28,6 +30,7 @@ + + logger = logging.getLogger(__name__) + ++ + class TestIPACommand(IntegrationTest): + """ + A lot of commands can be executed against a single IPA installation +@@ -429,3 +432,31 @@ def test_certificate_out_write_to_file(self): + x509.load_pem_x509_certificate(data, backend=default_backend()) + + self.master.run_command(['rm', '-f', filename]) ++ ++ def test_sssd_ifp_access_ipaapi(self): ++ # check that ipaapi is allowed to access sssd-ifp for smartcard auth ++ # https://pagure.io/freeipa/issue/7751 ++ username = 'admin' ++ # get UID for user ++ result = self.master.run_command(['ipa', 'user-show', username]) ++ mo = re.search(r'UID: (\d+)', result.stdout_text) ++ assert mo is not None, result.stdout_text ++ uid = mo.group(1) ++ ++ cmd = [ ++ 'dbus-send', ++ '--print-reply', '--system', ++ '--dest=org.freedesktop.sssd.infopipe', ++ '/org/freedesktop/sssd/infopipe/Users', ++ 'org.freedesktop.sssd.infopipe.Users.FindByName', ++ 'string:{}'.format(username) ++ ] ++ # test IFP as root ++ result = self.master.run_command(cmd) ++ assert uid in result.stdout_text ++ ++ # test IFP as ipaapi ++ result = self.master.run_command( ++ ['sudo', '-u', IPAAPI_USER, '--'] + cmd ++ ) ++ assert uid in result.stdout_text +From eb0136ea3438b6fb1145456478f401b9b7467cba Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 16 Nov 2018 14:11:16 +0100 +Subject: [PATCH] Remove dead code + +set_sssd_domain_option() is no longer used. Changes are handled by +sssd_update(). + +See: https://pagure.io/freeipa/issue/7751 +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaserver/install/server/upgrade.py | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index f1e78beb27..71bdd3670c 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1399,15 +1399,6 @@ def fix_schema_file_syntax(): + sysupgrade.set_upgrade_state('ds', 'fix_schema_syntax', True) + + +-def set_sssd_domain_option(option, value): +- sssdconfig = SSSDConfig.SSSDConfig() +- sssdconfig.import_config() +- domain = sssdconfig.get_domain(str(api.env.domain)) +- domain.set_option(option, value) +- sssdconfig.save_domain(domain) +- sssdconfig.write(paths.SSSD_CONF) +- +- + def sssd_update(): + sssdconfig = SSSDConfig.SSSDConfig() + sssdconfig.import_config() +From 415295a6f68f4c797529e19a3f0cf956619d4bed Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 16 Nov 2018 14:51:23 +0100 +Subject: [PATCH] Allow HTTPd user to access SSSD IFP + +For smart card and certificate authentication, Apache's +mod_lookup_identity module must be able to acess SSSD IFP. The module +accesses IFP as Apache user, not as ipaapi user. + +Apache is not allowed to use IFP by default. The update code uses the +service's ok-to-auth-as-delegate flag to detect smart card / cert auth. + +See: https://pagure.io/freeipa/issue/7751 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaclient/install/client.py | 10 +++++++++- + ipaserver/install/server/upgrade.py | 11 ++++++++++- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index f9b003ef57..6125588802 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -47,6 +47,7 @@ + verify_host_resolvable, + ) + from ipaplatform import services ++from ipaplatform.constants import constants + from ipaplatform.paths import paths + from ipaplatform.tasks import tasks + from ipapython import certdb, kernel_keyring, ipaldap, ipautil +@@ -1038,8 +1039,13 @@ def sssd_enable_service(sssdconfig, name): + return sssdconfig.get_service(name) + + +-def sssd_enable_ifp(sssdconfig): ++def sssd_enable_ifp(sssdconfig, allow_httpd=False): + """Enable and configure libsss_simpleifp plugin ++ ++ Allow the ``ipaapi`` user to access IFP. In case allow_httpd is true, ++ the Apache HTTPd user is also allowed to access IFP. For smart card ++ authentication, mod_lookup_identity must be allowed to access user ++ information. + """ + service = sssd_enable_service(sssdconfig, 'ifp') + if service is None: +@@ -1058,6 +1064,8 @@ def sssd_enable_ifp(sssdconfig): + uids.add('root') + # allow IPA API to access IFP + uids.add(IPAAPI_USER) ++ if allow_httpd: ++ uids.add(constants.HTTPD_USER) + service.set_option('allowed_uids', ', '.join(sorted(uids))) + sssdconfig.save_service(service) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 71bdd3670c..4de7fd974d 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1407,8 +1407,17 @@ def sssd_update(): + domain.set_option('ipa_server_mode', 'True') + domain.set_option('ipa_server', api.env.host) + sssdconfig.save_domain(domain) ++ # check if service has ok_to_auth_as_delegate ++ service = 'HTTP/{}'.format(api.env.host) ++ result = api.Command.service_show(service, all=True) ++ flag = result['result'].get('ipakrboktoauthasdelegate', False) ++ if flag: ++ logger.debug( ++ "%s has ok_to_auth_as_delegate, allow Apache to access IFP", ++ services ++ ) + # enable and configure IFP plugin +- sssd_enable_ifp(sssdconfig) ++ sssd_enable_ifp(sssdconfig, allow_httpd=flag) + # write config and restart service + sssdconfig.write(paths.SSSD_CONF) + sssd = services.service('sssd', api) +From d7d17ece57ae1322c8368b7853f24d56b1d6a150 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 16 Nov 2018 14:54:32 +0100 +Subject: [PATCH] Smart card auth advise: Allow Apache user + +Modify the smard card auth advise script to use sssd_enable_ifp() in +order to allow Apache to access SSSD IFP. + +See: https://pagure.io/freeipa/issue/7751 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaserver/advise/plugins/smart_card_auth.py | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/advise/plugins/smart_card_auth.py b/ipaserver/advise/plugins/smart_card_auth.py +index 97e23303b0..9a7a315ed5 100644 +--- a/ipaserver/advise/plugins/smart_card_auth.py ++++ b/ipaserver/advise/plugins/smart_card_auth.py +@@ -105,6 +105,7 @@ class config_server_for_smart_card_auth(common_smart_card_auth_config): + ssl_conf = paths.HTTPD_SSL_CONF + ssl_ocsp_directive = OCSP_DIRECTIVE + kdc_service_name = services.knownservices.krb5kdc.systemd_name ++ httpd_service_name = services.knownservices.httpd.systemd_name + + def get_info(self): + self.log.exit_on_nonroot_euid() +@@ -117,6 +118,7 @@ def get_info(self): + self.record_httpd_ocsp_status() + self.check_and_enable_pkinit() + self.enable_ok_to_auth_as_delegate_on_http_principal() ++ self.allow_httpd_ifp() + self.upload_smartcard_ca_certificates_to_systemwide_db() + self.install_smart_card_signing_ca_certs() + self.update_ipa_ca_certificate_store() +@@ -183,7 +185,9 @@ def _format_command(self, fmt_line, directive, filename): + + def restart_httpd(self): + self.log.comment('finally restart apache') +- self.log.command('systemctl restart httpd') ++ self.log.command( ++ 'systemctl restart {}'.format(self.httpd_service_name) ++ ) + + def record_httpd_ocsp_status(self): + self.log.comment('store the OCSP upgrade state') +@@ -214,6 +218,21 @@ def enable_ok_to_auth_as_delegate_on_http_principal(self): + ["Failed to set OK_AS_AUTH_AS_DELEGATE flag on HTTP principal"] + ) + ++ def allow_httpd_ifp(self): ++ self.log.comment('Allow Apache to access SSSD IFP') ++ self.log.exit_on_failed_command( ++ '{} -c "import SSSDConfig; ' ++ 'from ipaclient.install.client import sssd_enable_ifp; ' ++ 'from ipaplatform.paths import paths; ' ++ 'c = SSSDConfig.SSSDConfig(); ' ++ 'c.import_config(); ' ++ 'sssd_enable_ifp(c, allow_httpd=True); ' ++ 'c.write(paths.SSSD_CONF)"'.format(sys.executable), ++ ['Failed to modify SSSD config'] ++ ) ++ self.log.comment('Restart sssd') ++ self.log.command('systemctl restart sssd') ++ + def restart_kdc(self): + self.log.exit_on_failed_command( + 'systemctl restart {}'.format(self.kdc_service_name), +From b56db8daa704782c44683412b85a454654eabc19 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Mon, 19 Nov 2018 14:19:16 +0100 +Subject: [PATCH] Log stderr in run_command + +pytest_multihost's run_command() does not log stderr when a command +fails. Wrap the function call to log stderr so it's easier to debug +failing tests. + +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipatests/pytest_ipa/integration/host.py | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/ipatests/pytest_ipa/integration/host.py b/ipatests/pytest_ipa/integration/host.py +index 28f6e2cd32..6aed58ae96 100644 +--- a/ipatests/pytest_ipa/integration/host.py ++++ b/ipatests/pytest_ipa/integration/host.py +@@ -18,6 +18,7 @@ + # along with this program. If not, see . + + """Host class for integration testing""" ++import subprocess + + import pytest_multihost.host + +@@ -60,6 +61,24 @@ def to_env(self, **kwargs): + from ipatests.pytest_ipa.integration.env_config import host_to_env + return host_to_env(self, **kwargs) + ++ def run_command(self, argv, set_env=True, stdin_text=None, ++ log_stdout=True, raiseonerr=True, ++ cwd=None, bg=False, encoding='utf-8'): ++ # Wrap run_command to log stderr on raiseonerr=True ++ result = super().run_command( ++ argv, set_env=set_env, stdin_text=stdin_text, ++ log_stdout=log_stdout, raiseonerr=False, cwd=cwd, bg=bg, ++ encoding=encoding ++ ) ++ if result.returncode and raiseonerr: ++ result.log.error('stderr: %s', result.stderr_text) ++ raise subprocess.CalledProcessError( ++ result.returncode, argv, ++ result.stdout_text, result.stderr_text ++ ) ++ else: ++ return result ++ + + class WinHost(pytest_multihost.host.WinHost): + """ +From 97776d2c4eed5de73780476bb11a635a2e47ebc5 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 21 Nov 2018 10:00:20 +0100 +Subject: [PATCH] Test smart card advise scripts + +Create and execute the server and client smart card advise scripts. + +See: See: https://pagure.io/freeipa/issue/7751 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipatests/prci_definitions/gating.yaml | 2 +- + ipatests/test_integration/test_advise.py | 99 ++++++++++++++++++------ + 2 files changed, 75 insertions(+), 26 deletions(-) + +diff --git a/ipatests/prci_definitions/gating.yaml b/ipatests/prci_definitions/gating.yaml +index 7a9b612dea..13f8851d02 100644 +--- a/ipatests/prci_definitions/gating.yaml ++++ b/ipatests/prci_definitions/gating.yaml +@@ -157,7 +157,7 @@ jobs: + test_suite: test_integration/test_advise.py + template: *ci-master-f29 + timeout: 3600 +- topology: *master_1repl ++ topology: *master_1repl_1client + + fedora-29/test_testconfig: + requires: [fedora-29/build] +diff --git a/ipatests/test_integration/test_advise.py b/ipatests/test_integration/test_advise.py +index 3b821c8797..b548614922 100644 +--- a/ipatests/test_integration/test_advise.py ++++ b/ipatests/test_integration/test_advise.py +@@ -21,11 +21,17 @@ + # pylint: disable=no-member + + import re ++ ++from ipalib.constants import IPAAPI_USER ++from ipaplatform.paths import paths ++from ipaplatform.constants import constants ++ ++from ipatests.create_external_ca import ExternalCA + from ipatests.pytest_ipa.integration import tasks + from ipatests.test_integration.base import IntegrationTest + + +-def run_advice(master, advice_id, advice_regex, raiseerr): ++def run_advice(master, advice_id, advice_regex, raiseerr=True): + # Obtain the advice from the server + tasks.kinit_admin(master) + result = master.run_command(['ipa-advise', advice_id], +@@ -43,28 +49,38 @@ class TestAdvice(IntegrationTest): + """ + Tests ipa-advise output. + """ +- advice_id = None +- raiseerr = None +- advice_regex = '' + topology = 'line' ++ num_replicas = 0 ++ num_clients = 1 ++ ++ def execute_advise(self, host, advice_id, *args): ++ # ipa-advise script is only available on a server ++ tasks.kinit_admin(self.master) ++ advice = self.master.run_command(['ipa-advise', advice_id]) ++ # execute script on host (client or master) ++ if host is not self.master: ++ tasks.kinit_admin(host) ++ filename = tasks.upload_temp_contents(host, advice.stdout_text) ++ cmd = ['sh', filename] ++ cmd.extend(args) ++ try: ++ result = host.run_command(cmd) ++ finally: ++ host.run_command(['rm', '-f', filename]) ++ return advice, result + + def test_invalid_advice(self): + advice_id = r'invalid-advise-param' + advice_regex = r"invalid[\s]+\'advice\'.*" +- raiseerr = False +- +- run_advice(self.master, advice_id, advice_regex, raiseerr) +- ++ run_advice(self.master, advice_id, advice_regex, raiseerr=False) + + def test_advice_FreeBSDNSSPAM(self): + advice_id = 'config-freebsd-nss-pam-ldapd' + advice_regex = r"\#\!\/bin\/sh.*" \ + r"pkg_add[\s]+\-r[\s]+nss\-pam\-ldapd[\s]+curl.*" \ + r"\/usr\/local\/etc\/rc\.d\/nslcd[\s]+restart" +- raiseerr = True +- +- run_advice(self.master, advice_id, advice_regex, raiseerr) + ++ run_advice(self.master, advice_id, advice_regex) + + def test_advice_GenericNSSPAM(self): + advice_id = 'config-generic-linux-nss-pam-ldapd' +@@ -75,20 +91,16 @@ def test_advice_GenericNSSPAM(self): + r"service[\s]+nscd[\s]+stop[\s]+\&\&[\s]+service[\s]+" + r"nslcd[\s]+restart" + ) +- raiseerr = True +- +- run_advice(self.master, advice_id, advice_regex, raiseerr) + ++ run_advice(self.master, advice_id, advice_regex) + + def test_advice_GenericSSSDBefore19(self): + advice_id = r'config-generic-linux-sssd-before-1-9' + advice_regex = r"\#\!\/bin\/sh.*" \ + r"apt\-get[\s]+\-y[\s]+install sssd curl openssl.*" \ + r"service[\s]+sssd[\s]+start" +- raiseerr = True +- +- run_advice(self.master, advice_id, advice_regex, raiseerr) + ++ run_advice(self.master, advice_id, advice_regex) + + def test_advice_RedHatNSS(self): + advice_id = 'config-redhat-nss-ldap' +@@ -100,10 +112,8 @@ def test_advice_RedHatNSS(self): + r"[\s]+\-\-enableldapauth[\s]+" + r"\-\-ldapserver=.*[\s]+\-\-ldapbasedn=.*" + ) +- raiseerr = True +- +- run_advice(self.master, advice_id, advice_regex, raiseerr) + ++ run_advice(self.master, advice_id, advice_regex) + + def test_advice_RedHatNSSPAM(self): + advice_id = 'config-redhat-nss-pam-ldapd' +@@ -113,10 +123,8 @@ def test_advice_RedHatNSSPAM(self): + r"authconfig[\s]+\-\-updateall[\s]+\-\-enableldap"\ + r"[\s]+\-\-enableldaptls[\s]+\-\-enableldapauth[\s]+" \ + r"\-\-ldapserver=.*[\s]+\-\-ldapbasedn=.*" +- raiseerr = True +- +- run_advice(self.master, advice_id, advice_regex, raiseerr) + ++ run_advice(self.master, advice_id, advice_regex) + + def test_advice_RedHatSSSDBefore19(self): + advice_id = 'config-redhat-sssd-before-1-9' +@@ -125,6 +133,47 @@ def test_advice_RedHatSSSDBefore19(self): + r"yum[\s]+install[\s]+\-y[\s]+sssd[\s]+authconfig[\s]+" + r"curl[\s]+openssl.*service[\s]+sssd[\s]+start" + ) +- raiseerr = True + +- run_advice(self.master, advice_id, advice_regex, raiseerr) ++ run_advice(self.master, advice_id, advice_regex) ++ ++ # trivial checks ++ def test_advice_enable_admins_sudo(self): ++ advice_id = 'enable_admins_sudo' ++ advice_regex = r"\#\!\/bin\/sh.*" ++ run_advice(self.master, advice_id, advice_regex) ++ ++ def test_advice_config_server_for_smart_card_auth(self): ++ advice_id = 'config_server_for_smart_card_auth' ++ advice_regex = r"\#\!\/bin\/sh.*" ++ run_advice(self.master, advice_id, advice_regex) ++ ++ ca_pem = ExternalCA().create_ca() ++ ca_file = tasks.upload_temp_contents(self.master, ca_pem) ++ try: ++ self.execute_advise(self.master, advice_id, ca_file) ++ except Exception: ++ # debug: sometimes ipa-certupdate times out in ++ # "Resubmitting certmonger request" ++ self.master.run_command(['getcert', 'list']) ++ raise ++ finally: ++ self.master.run_command(['rm', '-f', ca_file]) ++ sssd_conf = self.master.get_file_contents( ++ paths.SSSD_CONF, encoding='utf-8' ++ ) ++ assert constants.HTTPD_USER in sssd_conf ++ assert IPAAPI_USER in sssd_conf ++ ++ def test_advice_config_client_for_smart_card_auth(self): ++ advice_id = 'config_client_for_smart_card_auth' ++ advice_regex = r"\#\!\/bin\/sh.*" ++ run_advice(self.master, advice_id, advice_regex) ++ ++ client = self.clients[0] ++ ++ ca_pem = ExternalCA().create_ca() ++ ca_file = tasks.upload_temp_contents(client, ca_pem) ++ try: ++ self.execute_advise(client, advice_id, ca_file) ++ finally: ++ client.run_command(['rm', '-f', ca_file]) +From 6ed90a2ac08c070e8e5c47a1eb3c52d7d30cabb8 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 21 Nov 2018 10:44:55 +0100 +Subject: [PATCH] Add install/remove package helpers to advise + +The smart card advise scripts assume that yum is installed. However +Fedora has dnf and the yum wrapper is not installed by default. +Installation and removal of packages is now provided by two helper +methods that detect the package manager. + +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaserver/advise/base.py | 36 +++++++++++++++++++++ + ipaserver/advise/plugins/smart_card_auth.py | 24 +++++++------- + 2 files changed, 47 insertions(+), 13 deletions(-) + +diff --git a/ipaserver/advise/base.py b/ipaserver/advise/base.py +index 07b1431e84..ec65113e34 100644 +--- a/ipaserver/advise/base.py ++++ b/ipaserver/advise/base.py +@@ -227,6 +227,7 @@ def __init__(self): + self.content = [] + self.prefix = '# ' + self.options = None ++ self.pkgmgr_detected = False + self._indentation_tracker = _IndentationTracker( + spaces_per_indent=DEFAULT_INDENTATION_INCREMENT) + +@@ -312,6 +313,41 @@ def exit_on_predicate(self, predicate, error_message_lines): + + self.command('exit 1') + ++ def detect_pkgmgr(self): ++ self.commands_on_predicate( ++ 'which yum >/dev/null', ++ commands_to_run_when_true=['PKGMGR=yum'], ++ commands_to_run_when_false=['PKGMGR=dnf'] ++ ) ++ self.pkgmgr_detected = True ++ ++ def install_packages(self, names, error_message_lines): ++ assert isinstance(names, list) ++ self.detect_pkgmgr() ++ self.command('rpm -qi {} > /dev/null'.format(' '.join(names))) ++ self.commands_on_predicate( ++ '[ "$?" -ne "0" ]', ++ ['$PKGMGR install -y {}'.format(' '.join(names))] ++ ) ++ self.exit_on_predicate( ++ '[ "$?" -ne "0" ]', ++ error_message_lines ++ ) ++ ++ def remove_package(self, name, error_message_lines): ++ # remove only supports one package name ++ assert ' ' not in name ++ self.detect_pkgmgr() ++ self.command('rpm -qi {} > /dev/null'.format(name)) ++ self.commands_on_predicate( ++ '[ "$?" -eq "0" ]', ++ ['$PKGMGR remove -y {} || exit 1'.format(name)] ++ ) ++ self.exit_on_predicate( ++ '[ "$?" -ne "0" ]', ++ error_message_lines ++ ) ++ + @contextmanager + def unbranched_if(self, predicate): + with self._compound_statement(UnbranchedIfStatement, predicate): +diff --git a/ipaserver/advise/plugins/smart_card_auth.py b/ipaserver/advise/plugins/smart_card_auth.py +index 9a7a315ed5..411124f935 100644 +--- a/ipaserver/advise/plugins/smart_card_auth.py ++++ b/ipaserver/advise/plugins/smart_card_auth.py +@@ -135,9 +135,10 @@ def resolve_ipaca_records(self): + + self.log.comment('make sure bind-utils are installed so that we can ' + 'dig for ipa-ca records') +- self.log.exit_on_failed_command( +- 'yum install -y bind-utils', +- ['Failed to install bind-utils']) ++ self.log.install_packages( ++ ['bind-utils'], ++ ['Failed to install bind-utils'] ++ ) + + self.log.comment('make sure ipa-ca records are resolvable, ' + 'otherwise error out and instruct') +@@ -272,26 +273,23 @@ def get_info(self): + self.restart_sssd() + + def check_and_remove_pam_pkcs11(self): +- self.log.command('rpm -qi pam_pkcs11 > /dev/null') +- self.log.commands_on_predicate( +- '[ "$?" -eq "0" ]', +- [ +- 'yum remove -y pam_pkcs11' +- ] ++ self.log.remove_package( ++ 'pam_pkcs11', ++ ['Could not remove pam_pkcs11 package'] + ) + + def install_opensc_and_dconf_packages(self): + self.log.comment( + 'authconfig often complains about missing dconf, ' + 'install it explicitly') +- self.log.exit_on_failed_command( +- 'yum install -y {} dconf'.format(self.opensc_module_name.lower()), ++ self.log.install_packages( ++ [self.opensc_module_name.lower(), 'dconf'], + ['Could not install OpenSC package'] + ) + + def install_krb5_client_dependencies(self): +- self.log.exit_on_failed_command( +- 'yum install -y krb5-pkinit-openssl', ++ self.log.install_packages( ++ ['krb5-pkinit-openssl'], + ['Failed to install Kerberos client PKINIT extensions.'] + ) + +From e05ce4a20d2395179580db7e3db75c601c8f364c Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 13 Dec 2018 14:40:44 +0100 +Subject: [PATCH] Python 2 compatibility + +Make new test helpers and test code compatible with Python 2.7. + +See: https://pagure.io/freeipa/issue/7751 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipatests/pytest_ipa/integration/host.py | 4 ++-- + ipatests/test_integration/test_advise.py | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/ipatests/pytest_ipa/integration/host.py b/ipatests/pytest_ipa/integration/host.py +index 6aed58ae96..eb05872467 100644 +--- a/ipatests/pytest_ipa/integration/host.py ++++ b/ipatests/pytest_ipa/integration/host.py +@@ -65,7 +65,7 @@ def run_command(self, argv, set_env=True, stdin_text=None, + log_stdout=True, raiseonerr=True, + cwd=None, bg=False, encoding='utf-8'): + # Wrap run_command to log stderr on raiseonerr=True +- result = super().run_command( ++ result = super(Host, self).run_command( + argv, set_env=set_env, stdin_text=stdin_text, + log_stdout=log_stdout, raiseonerr=False, cwd=cwd, bg=bg, + encoding=encoding +@@ -74,7 +74,7 @@ def run_command(self, argv, set_env=True, stdin_text=None, + result.log.error('stderr: %s', result.stderr_text) + raise subprocess.CalledProcessError( + result.returncode, argv, +- result.stdout_text, result.stderr_text ++ result.stderr_text + ) + else: + return result +diff --git a/ipatests/test_integration/test_advise.py b/ipatests/test_integration/test_advise.py +index b548614922..761f278238 100644 +--- a/ipatests/test_integration/test_advise.py ++++ b/ipatests/test_integration/test_advise.py +@@ -20,6 +20,8 @@ + # FIXME: Pylint errors + # pylint: disable=no-member + ++from __future__ import absolute_import ++ + import re + + from ipalib.constants import IPAAPI_USER diff --git a/SOURCES/0015-Add_sysadm_r_to_default_SELinux_user_map_order_1853e2e_rhbz#1658303.patch b/SOURCES/0015-Add_sysadm_r_to_default_SELinux_user_map_order_1853e2e_rhbz#1658303.patch new file mode 100644 index 0000000..47c9744 --- /dev/null +++ b/SOURCES/0015-Add_sysadm_r_to_default_SELinux_user_map_order_1853e2e_rhbz#1658303.patch @@ -0,0 +1,61 @@ +From 1853e2ecd6b5cbe389507a8c3fc751deaf512bb6 Mon Sep 17 00:00:00 2001 +From: François Cami +Date: Nov 12 2018 07:52:27 +0000 +Subject: Add sysadm_r to default SELinux user map order + + +It is a standard SELinux user role included in RHEL (like +user_r, staff_r, guest_r) and used quite often. + +Fixes: https://pagure.io/freeipa/issue/7658 +Signed-off-by: François Cami +Reviewed-By: Rob Crittenden + +--- + +diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif +index ea1e5b2..8cc79d1 100644 +--- a/install/share/bootstrap-template.ldif ++++ b/install/share/bootstrap-template.ldif +@@ -411,7 +411,7 @@ ipaDefaultEmailDomain: $DOMAIN + ipaMigrationEnabled: FALSE + ipaConfigString: AllowNThash + ipaConfigString: KDC:Disable Last Success +-ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 ++ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$sysadm_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 + ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023 + + dn: cn=cosTemplates,cn=accounts,$SUFFIX +diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json +index 71c9d73..4298f7d 100644 +--- a/install/ui/test/data/ipa_init.json ++++ b/install/ui/test/data/ipa_init.json +@@ -36,7 +36,7 @@ + "ipausers" + ], + "ipaselinuxusermaporder" : [ +- "guest_u:s0$xguest_u:s0$user_u:s0$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023" ++ "guest_u:s0$xguest_u:s0$user_u:s0$staff_u:s0-s0:c0.c1023$sysadm_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023" + ], + "ca_renewal_master_server" : [ + "vm.example.com" +diff --git a/ipatests/test_xmlrpc/test_config_plugin.py b/ipatests/test_xmlrpc/test_config_plugin.py +index 049e44d..cb8cdeb 100644 +--- a/ipatests/test_xmlrpc/test_config_plugin.py ++++ b/ipatests/test_xmlrpc/test_config_plugin.py +@@ -148,8 +148,12 @@ class test_config(Declarative): + + dict( + desc='Try to set new selinux order and invalid default user', +- command=('config_mod', [], +- dict(ipaselinuxusermaporder=u'xguest_u:s0$guest_u:s0$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023', ++ command=( ++ 'config_mod', [], ++ dict( ++ ipaselinuxusermaporder=u'xguest_u:s0$guest_u:s0' ++ u'$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023' ++ u'$sysadm_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023', + ipaselinuxusermapdefault=u'unknown_u:s0')), + expected=errors.ValidationError(name='ipaselinuxusermapdefault', + error='SELinux user map default user not in order list'), + diff --git a/SOURCES/0016-certdb_non-empty_Subject_Key_Identifier_and_validate_server_cert_sig_rhbz#1641988.patch b/SOURCES/0016-certdb_non-empty_Subject_Key_Identifier_and_validate_server_cert_sig_rhbz#1641988.patch new file mode 100644 index 0000000..4ad95c1 --- /dev/null +++ b/SOURCES/0016-certdb_non-empty_Subject_Key_Identifier_and_validate_server_cert_sig_rhbz#1641988.patch @@ -0,0 +1,78 @@ +From c7cc9896e89b3214c439e5601bf93b405dc1c72b Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Mon, 12 Nov 2018 16:40:38 +1100 +Subject: [PATCH] certdb: ensure non-empty Subject Key Identifier + +Installation or IPA CA renewal with externally-signed CA accepts an +IPA CA certificate with empty Subject Key Identifier. This is +technically legal in X.509, but is an operational issue. +Furthermore, due to an extant bug in Dogtag +(https://pagure.io/dogtagpki/issue/3079) it will cause Dogtag +startup failure. + +Reject CA certificates with empty Subject Key Identifier. + +Fixes: https://pagure.io/freeipa/issue/7762 +Reviewed-By: Christian Heimes +--- + ipapython/certdb.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index e3f00c2561..bef6809b0f 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -919,10 +919,13 @@ def verify_ca_cert_validity(self, nickname): + raise ValueError("not a CA certificate") + + try: +- cert.extensions.get_extension_for_class( ++ ski = cert.extensions.get_extension_for_class( + cryptography.x509.SubjectKeyIdentifier) + except cryptography.x509.ExtensionNotFound: + raise ValueError("missing subject key identifier extension") ++ else: ++ if len(ski.value.digest) == 0: ++ raise ValueError("subject key identifier must not be empty") + + try: + self.run_certutil(['-V', '-n', nickname, '-u', 'L'], +From c2ae6380b3f6b3804ebd2a7dd2b159b779eb756c Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Tue, 13 Nov 2018 12:21:21 +0100 +Subject: [PATCH] certdb: validate server cert signature + +PR https://github.com/freeipa/freeipa/pull/2554 added the '-e' option for CA +cert validation. Let's also verify signature, key size, and signing algorithm +of server certs. With the '-e' option, the installer and other +tools will catch weak certs early. + +Fixes: pagure.io/freeipa/issue/7761 +Signed-off-by: Christian Heimes +Reviewed-By: Fraser Tweedale +--- + ipapython/certdb.py | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index 05ec932985..1a92a12c50 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -891,8 +891,15 @@ def verify_server_cert_validity(self, nickname, hostname): + cert = self.get_cert(nickname) + + try: +- self.run_certutil(['-V', '-n', nickname, '-u', 'V'], +- capture_output=True) ++ self.run_certutil( ++ [ ++ '-V', # check validity of cert and attrs ++ '-n', nickname, ++ '-u', 'V', # usage; 'V' means "SSL server" ++ '-e', # check signature(s); this checks ++ # key sizes, sig algorithm, etc. ++ ], ++ capture_output=True) + except ipautil.CalledProcessError as e: + # certutil output in case of error is + # 'certutil: certificate is invalid: \n' diff --git a/SOURCES/0017-ipa-replica-install_password_and_admin-password_options_mutually_exclusive_rhbz#1658309.patch b/SOURCES/0017-ipa-replica-install_password_and_admin-password_options_mutually_exclusive_rhbz#1658309.patch new file mode 100644 index 0000000..8015afd --- /dev/null +++ b/SOURCES/0017-ipa-replica-install_password_and_admin-password_options_mutually_exclusive_rhbz#1658309.patch @@ -0,0 +1,84 @@ +From fd3f5153beb3221be077f277b07d886b6ca53b10 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Nov 21 2018 03:21:29 +0000 +Subject: ipa-replica-install: password and admin-password options mutually exclusive + + +Currently it is possible to run ipa-replica-install in one step, +and provide --password and --admin-password simultaneously. +This is confusing as --password is intended for one-time pwd +when the ipa-replica-install command is delegated to a user +who doesn't know the admin password. + +The fix makes --password and --admin-password options +mutually exclusive. + +Fixes https://pagure.io/freeipa/issue/6353 + +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 03d096d..d3e28a1 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -771,6 +771,10 @@ def promote_check(installer): + + client_fstore = sysrestore.FileStore(paths.IPA_CLIENT_SYSRESTORE) + if not client_fstore.has_files(): ++ # One-step replica installation ++ if options.password and options.admin_password: ++ raise ScriptError("--password and --admin-password options are " ++ "mutually exclusive") + ensure_enrolled(installer) + else: + if (options.domain_name or options.server or options.realm_name or + +From 2b155f98e7b9ced739233242ff53e2d4b4c7f063 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Nov 21 2018 03:21:29 +0000 +Subject: ipatests: add test for ipa-replica-install options + + +Add a test checking that --password and --admin-password +options are mutually exclusive. + +Related to https://pagure.io/freeipa/issue/6353 + +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py +index 7803c34..e665318 100644 +--- a/ipatests/test_integration/test_replica_promotion.py ++++ b/ipatests/test_integration/test_replica_promotion.py +@@ -50,6 +50,26 @@ class TestReplicaPromotionLevel1(ReplicaPromotionBase): + domain_level = DOMAIN_LEVEL_1 + + @replicas_cleanup ++ def test_one_step_install_pwd_and_admin_pwd(self): ++ """--password and --admin-password options are mutually exclusive ++ ++ Test for ticket 6353 ++ """ ++ expected_err = "--password and --admin-password options are " \ ++ "mutually exclusive" ++ result = self.replicas[0].run_command([ ++ 'ipa-replica-install', '-w', ++ self.master.config.admin_password, ++ '-p', 'OTPpwd', ++ '-n', self.master.domain.name, ++ '-r', self.master.domain.realm, ++ '--server', self.master.hostname, ++ '-U'], ++ raiseonerr=False) ++ assert result.returncode == 1 ++ assert expected_err in result.stderr_text ++ ++ @replicas_cleanup + def test_one_command_installation(self): + """ + TestCase: + diff --git a/SOURCES/0018-ipa_upgrade_handle_double-encoded_certificates_rhbz#1658310.patch b/SOURCES/0018-ipa_upgrade_handle_double-encoded_certificates_rhbz#1658310.patch new file mode 100644 index 0000000..19ab348 --- /dev/null +++ b/SOURCES/0018-ipa_upgrade_handle_double-encoded_certificates_rhbz#1658310.patch @@ -0,0 +1,153 @@ +From 8ee3779ded64ff55c3981fb8c2db50cdcd3abc5b Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Nov 30 2018 14:20:59 +0000 +Subject: ipa upgrade: handle double-encoded certificates + + +Issue is linked to the ticket + #3477 LDAP upload CA cert sometimes double-encodes the value +In old FreeIPA releases (< 3.2), the upgrade plugin was encoding twice +the value of the certificate in cn=cacert,cn=ipa,cn=etc,$BASEDN. + +The fix for 3477 is only partial as it prevents double-encoding when a +new cert is uploaded but does not fix wrong values already present in LDAP. + +With this commit, the code first tries to read a der cert. If it fails, +it logs a debug message and re-writes the value caCertificate;binary +to repair the entry. + +Fixes https://pagure.io/freeipa/issue/7775 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py +index 85c67e7..763da1e 100644 +--- a/ipaserver/install/plugins/upload_cacrt.py ++++ b/ipaserver/install/plugins/upload_cacrt.py +@@ -115,7 +115,18 @@ class update_upload_cacrt(Updater): + entry.single_value['cACertificate;binary'] = ca_cert + ldap.add_entry(entry) + else: +- if b'' in entry['cACertificate;binary']: ++ force_write = False ++ try: ++ _cert_bin = entry['cACertificate;binary'] ++ except ValueError: ++ # BZ 1644874 ++ # sometimes the cert is badly stored, twice encoded ++ # force write to fix the value ++ logger.debug('Fixing the value of cACertificate;binary ' ++ 'in entry %s', entry.dn) ++ force_write = True ++ ++ if force_write or b'' in entry['cACertificate;binary']: + entry.single_value['cACertificate;binary'] = ca_cert + ldap.update_entry(entry) + + +From 2b0f3a1abb9067a0a5ba8e59762bc41dc51608e2 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Nov 30 2018 14:20:59 +0000 +Subject: ipatests: add upgrade test for double-encoded cacert + + +Create a test for upgrade with the following scenario: +- install master +- write a double-encoded cert in the entry +cn=cacert,,cn=ipa,cn=etc,$basedn +to simulate bug 7775 +- call ipa-server-upgrade +- check that the upgrade fixed the value + +The upgrade should finish successfully and repair +the double-encoded cert. + +Related to https://pagure.io/freeipa/issue/7775 + +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipatests/test_integration/test_upgrade.py b/ipatests/test_integration/test_upgrade.py +index cbf5f39..e0175bc 100644 +--- a/ipatests/test_integration/test_upgrade.py ++++ b/ipatests/test_integration/test_upgrade.py +@@ -6,6 +6,9 @@ + Module provides tests to verify that the upgrade script works. + """ + ++import base64 ++from cryptography.hazmat.primitives import serialization ++from ipapython.dn import DN + from ipatests.test_integration.base import IntegrationTest + from ipatests.pytest_ipa.integration import tasks + +@@ -21,3 +24,35 @@ class TestUpgrade(IntegrationTest): + assert ("DN: cn=Schema Compatibility,cn=plugins,cn=config does not \ + exists or haven't been updated" not in cmd.stdout_text) + assert cmd.returncode == 0 ++ ++ def test_double_encoded_cacert(self): ++ """Test for BZ 1644874 ++ ++ In old IPA version, the entry cn=CAcert,cn=ipa,cn=etc,$basedn ++ could contain a double-encoded cert, which leads to ipa-server-upgrade ++ failure. ++ Force a double-encoded value then call upgrade to check the fix. ++ """ ++ # Read the current entry from LDAP ++ ldap = self.master.ldap_connect() ++ basedn = self.master.domain.basedn # pylint: disable=no-member ++ dn = DN(('cn', 'CAcert'), ('cn', 'ipa'), ('cn', 'etc'), basedn) ++ entry = ldap.get_entry(dn) # pylint: disable=no-member ++ # Extract the certificate as DER then double-encode ++ cacert = entry['cacertificate;binary'][0] ++ cacert_der = cacert.public_bytes(serialization.Encoding.DER) ++ cacert_b64 = base64.b64encode(cacert_der) ++ # overwrite the value with double-encoded cert ++ entry.single_value['cACertificate;binary'] = cacert_b64 ++ ldap.update_entry(entry) # pylint: disable=no-member ++ ++ # try the upgrade ++ self.master.run_command(['ipa-server-upgrade']) ++ ++ # read the value after upgrade, should be fixed ++ entry = ldap.get_entry(dn) # pylint: disable=no-member ++ try: ++ _cacert = entry['cacertificate;binary'] ++ except ValueError: ++ raise AssertionError('%s contains a double-encoded cert' ++ % entry.dn) + +From 2a299c786f93e67446d5fd227fe14884b4e0d293 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Dec 06 2018 10:37:26 +0000 +Subject: ipatests: fix TestUpgrade::test_double_encoded_cacert + + +The test is using a stale ldap connection to the master +(obtained before calling upgrade, and the upgrade stops +and starts 389-ds, breaking the connection). + +The fix re-connects before using the ldap handle. + +Related to https://pagure.io/freeipa/issue/7775 + +--- + +diff --git a/ipatests/test_integration/test_upgrade.py b/ipatests/test_integration/test_upgrade.py +index e0175bc..5cc890e 100644 +--- a/ipatests/test_integration/test_upgrade.py ++++ b/ipatests/test_integration/test_upgrade.py +@@ -49,6 +49,8 @@ class TestUpgrade(IntegrationTest): + # try the upgrade + self.master.run_command(['ipa-server-upgrade']) + ++ # reconnect to the master (upgrade stops 389-ds) ++ ldap = self.master.ldap_connect() + # read the value after upgrade, should be fixed + entry = ldap.get_entry(dn) # pylint: disable=no-member + try: + diff --git a/SOURCES/0019-PKINIT_fix_ipa-pkinit-manage_enable_disable_rhbz#1658313.patch b/SOURCES/0019-PKINIT_fix_ipa-pkinit-manage_enable_disable_rhbz#1658313.patch new file mode 100644 index 0000000..58c0d41 --- /dev/null +++ b/SOURCES/0019-PKINIT_fix_ipa-pkinit-manage_enable_disable_rhbz#1658313.patch @@ -0,0 +1,279 @@ +From 940755e37b06ea95c32abd056277da19fb05ed3e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Dec 06 2018 10:40:02 +0000 +Subject: ipatest: add test for ipa-pkinit-manage enable|disable + + +Add a test for ipa-pkinit-manage with the following scenario: +- install master with option --no-pkinit +- call ipa-pkinit-manage enable +- call ipa-pkinit-manage disable +- call ipa-pkinit-manage enable + +At each step, check that the PKINIT cert is consistent with the +expectations: when pkinit is enabled, the cert is signed by IPA +CA and tracked by 'IPA' ca helper, but when pkinit is disabled, +the cert is self-signed and tracked by 'SelfSign' CA helper. + +The new test is added in the nightly definitons. + +Related to https://pagure.io/freeipa/issue/7200 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Christian Heimes + +--- + +#diff --git a/ipatests/prci_definitions/nightly_f28.yaml b/ipatests/prci_definitions/nightly_f28.yaml +#index ae8cacc..8462c14 100644 +#--- a/ipatests/prci_definitions/nightly_f28.yaml +#+++ b/ipatests/prci_definitions/nightly_f28.yaml +#@@ -639,3 +639,15 @@ jobs: +# template: *ci-master-f28 +# timeout: 16000 +# topology: *ipaserver +#+ +#+ fedora-28/test_pkinit_manage: +#+ requires: [fedora-28/build] +#+ priority: 50 +#+ job: +#+ class: RunPytest +#+ args: +#+ build_url: '{fedora-28/build_url}' +#+ test_suite: test_integration/test_pkinit_manage.py +#+ template: *ci-master-f28 +#+ timeout: 3600 +#+ topology: *master_1repl +diff --git a/ipatests/prci_definitions/nightly_master.yaml b/ipatests/prci_definitions/nightly_master.yaml +index 66921b6..3f2b346 100644 +--- a/ipatests/prci_definitions/nightly_master.yaml ++++ b/ipatests/prci_definitions/nightly_master.yaml +@@ -639,3 +639,15 @@ jobs: + template: *ci-master-f29 + timeout: 16000 + topology: *ipaserver ++ ++ fedora-29/test_pkinit_manage: ++ requires: [fedora-29/build] ++ priority: 50 ++ job: ++ class: RunPytest ++ args: ++ build_url: '{fedora-29/build_url}' ++ test_suite: test_integration/test_pkinit_manage.py ++ template: *ci-master-f29 ++ timeout: 3600 ++ topology: *master_1repl +diff --git a/ipatests/prci_definitions/nightly_rawhide.yaml b/ipatests/prci_definitions/nightly_rawhide.yaml +index 24c26be..bdc34d2 100644 +--- a/ipatests/prci_definitions/nightly_rawhide.yaml ++++ b/ipatests/prci_definitions/nightly_rawhide.yaml +@@ -627,3 +627,15 @@ jobs: + template: *ci-master-frawhide + timeout: 7200 + topology: *ipaserver ++ ++ fedora-rawhide/test_pkinit_manage: ++ requires: [fedora-rawhide/build] ++ priority: 50 ++ job: ++ class: RunPytest ++ args: ++ build_url: '{fedora-rawhide/build_url}' ++ test_suite: test_integration/test_pkinit_manage.py ++ template: *ci-master-frawhide ++ timeout: 3600 ++ topology: *master_1repl +diff --git a/ipatests/test_integration/test_pkinit_manage.py b/ipatests/test_integration/test_pkinit_manage.py +new file mode 100644 +index 0000000..bc1d9e3 +--- /dev/null ++++ b/ipatests/test_integration/test_pkinit_manage.py +@@ -0,0 +1,111 @@ ++# ++# Copyright (C) 2018 FreeIPA Contributors see COPYING for license ++# ++ ++""" ++Module provides tests for the ipa-pkinit-manage command. ++""" ++ ++from __future__ import absolute_import ++ ++from ipalib import x509 ++from ipaplatform.paths import paths ++from ipapython.dn import DN ++from ipatests.test_integration.base import IntegrationTest ++from ipatests.pytest_ipa.integration import tasks ++ ++ ++SELFSIGNED_CA_HELPER = 'SelfSign' ++IPA_CA_HELPER = 'IPA' ++PKINIT_STATUS_ENABLED = 'enabled' ++PKINIT_STATUS_DISABLED = 'disabled' ++ ++ ++def check_pkinit_status(host, status): ++ """Ensures that ipa-pkinit-manage status returns the expected state""" ++ result = host.run_command(['ipa-pkinit-manage', 'status'], ++ raiseonerr=False) ++ assert result.returncode == 0 ++ assert 'PKINIT is {}'.format(status) in result.stdout_text ++ ++ ++def check_pkinit_tracking(host, ca_helper): ++ """Ensures that the PKINIT cert is tracked by the expected helper""" ++ result = host.run_command(['getcert', 'list', '-f', paths.KDC_CERT], ++ raiseonerr=False) ++ assert result.returncode == 0 ++ # Make sure that only one request exists ++ assert result.stdout_text.count('Request ID') == 1 ++ # Make sure that the right CA helper is used to track the cert ++ assert 'CA: {}'.format(ca_helper) in result.stdout_text ++ ++ ++def check_pkinit_cert_issuer(host, issuer): ++ """Ensures that the PKINIT cert is signed by the expected issuer""" ++ data = host.get_file_contents(paths.KDC_CERT) ++ pkinit_cert = x509.load_pem_x509_certificate(data) ++ # Make sure that the issuer is the expected one ++ assert DN(pkinit_cert.issuer) == DN(issuer) ++ ++ ++def check_pkinit(host, enabled=True): ++ """Checks that PKINIT is configured as expected ++ ++ If enabled: ++ ipa-pkinit-manage status must return 'PKINIT is enabled' ++ the certificate must be tracked by IPA CA helper ++ the certificate must be signed by IPA CA ++ If disabled: ++ ipa-pkinit-manage status must return 'PKINIT is disabled' ++ the certificate must be tracked by SelfSign CA helper ++ the certificate must be self-signed ++ """ ++ if enabled: ++ # When pkinit is enabled: ++ # cert is tracked by IPA CA helper ++ # cert is signed by IPA CA ++ check_pkinit_status(host, PKINIT_STATUS_ENABLED) ++ check_pkinit_tracking(host, IPA_CA_HELPER) ++ check_pkinit_cert_issuer( ++ host, ++ 'CN=Certificate Authority,O={}'.format(host.domain.realm)) ++ else: ++ # When pkinit is disabled ++ # cert is tracked by 'SelfSign' CA helper ++ # cert is self-signed ++ check_pkinit_status(host, PKINIT_STATUS_DISABLED) ++ check_pkinit_tracking(host, SELFSIGNED_CA_HELPER) ++ check_pkinit_cert_issuer( ++ host, ++ 'CN={},O={}'.format(host.hostname, host.domain.realm)) ++ ++ ++class TestPkinitManage(IntegrationTest): ++ """Tests the ipa-pkinit-manage command. ++ ++ ipa-pkinit-manage can be used to enable, disable or check ++ the status of PKINIT. ++ When pkinit is enabled, the kerberos server is using a certificate ++ signed either externally or by IPA CA. In the latter case, certmonger ++ is tracking the cert with IPA helper. ++ When pkinit is disabled, the kerberos server is using a self-signed ++ certificate that is tracked by certmonger with the SelfSigned helper. ++ """ ++ ++ @classmethod ++ def install(cls, mh): ++ # Install the master with PKINIT disabled ++ tasks.install_master(cls.master, extra_args=['--no-pkinit']) ++ check_pkinit(cls.master, enabled=False) ++ ++ def test_pkinit_enable(self): ++ self.master.run_command(['ipa-pkinit-manage', 'enable']) ++ check_pkinit(self.master, enabled=True) ++ ++ def test_pkinit_disable(self): ++ self.master.run_command(['ipa-pkinit-manage', 'disable']) ++ check_pkinit(self.master, enabled=False) ++ ++ def test_pkinit_reenable(self): ++ self.master.run_command(['ipa-pkinit-manage', 'enable']) ++ check_pkinit(self.master, enabled=True) + +From ffa04a1862be198b9e1a5f6205d1ae0909ac5a4d Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Dec 06 2018 10:40:02 +0000 +Subject: PKINIT: fix ipa-pkinit-manage enable|disable + + +The command ipa-pkinit-manage enable|disable is reporting +success even though the PKINIT cert is not re-issued. +The command triggers the request of a new certificate +(signed by IPA CA when state=enable, selfsigned when disabled), +but as the cert file is still present, certmonger does not create +a new request and the existing certificate is kept. + +The fix consists in deleting the cert and key file before calling +certmonger to request a new cert. + +There was also an issue in the is_pkinit_enabled() function: +if no tracking request was found for the PKINIT cert, +is_pkinit_enabled() was returning True while it should not. + +Fixes https://pagure.io/freeipa/issue/7200 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipaserver/install/ipa_pkinit_manage.py b/ipaserver/install/ipa_pkinit_manage.py +index 4a79bba..86bd1ba 100644 +--- a/ipaserver/install/ipa_pkinit_manage.py ++++ b/ipaserver/install/ipa_pkinit_manage.py +@@ -72,6 +72,8 @@ class PKINITManage(AdminTool): + if ca_enabled: + logger.warning( + "Failed to stop tracking certificates: %s", e) ++ # remove the cert and key ++ krb.delete_pkinit_cert() + + krb.enable_ssl() + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 4ead1c5..850946a 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -77,7 +77,7 @@ def is_pkinit_enabled(): + if os.path.exists(paths.KDC_CERT): + pkinit_request_ca = get_pkinit_request_ca() + +- if pkinit_request_ca != "SelfSign": ++ if pkinit_request_ca and pkinit_request_ca != "SelfSign": + return True + + return False +@@ -602,6 +602,10 @@ class KrbInstance(service.Service): + def stop_tracking_certs(self): + certmonger.stop_tracking(certfile=paths.KDC_CERT) + ++ def delete_pkinit_cert(self): ++ installutils.remove_file(paths.KDC_CERT) ++ installutils.remove_file(paths.KDC_KEY) ++ + def uninstall(self): + if self.is_configured(): + self.print_msg("Unconfiguring %s" % self.service_name) +@@ -627,8 +631,7 @@ class KrbInstance(service.Service): + # stop tracking and remove certificates + self.stop_tracking_certs() + installutils.remove_file(paths.CACERT_PEM) +- installutils.remove_file(paths.KDC_CERT) +- installutils.remove_file(paths.KDC_KEY) ++ self.delete_pkinit_cert() + + if running: + self.restart() + diff --git a/SOURCES/0020-Enable_LDAP_debug_output_in_client_to_display_TLS_errors_in_join_rhbz#1658316.patch b/SOURCES/0020-Enable_LDAP_debug_output_in_client_to_display_TLS_errors_in_join_rhbz#1658316.patch new file mode 100644 index 0000000..6b42e53 --- /dev/null +++ b/SOURCES/0020-Enable_LDAP_debug_output_in_client_to_display_TLS_errors_in_join_rhbz#1658316.patch @@ -0,0 +1,134 @@ +From be5513ba7d70cecba5aa7654b66c1aa4015f7de2 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 9 Oct 2018 17:13:36 -0400 +Subject: [PATCH] Enable LDAP debug output in client to display TLS errors in + join + +If ipa-join fails due to a TLS connection error when doing an +LDAP-based enroll then nothing is logged by default except an +Invalid Password error which is misleading (because the failure +occurs during the bind). + +The only way that debugging would have been sufficient is if +the user passed --debug to ipa-client-install which is not great. + +This log level is otherwise very quiet and only logs one or two +lines on errors which is perfect. + +https://pagure.io/freeipa/issue/7728 + +Signed-off-by: Rob Crittenden +Reviewed-By: Christian Heimes +--- + client/ipa-join.c | 64 ++++++++++++++++++++++++++--------------------- + 1 file changed, 35 insertions(+), 29 deletions(-) + +diff --git a/client/ipa-join.c b/client/ipa-join.c +index 7f454f723d..750114896f 100644 +--- a/client/ipa-join.c ++++ b/client/ipa-join.c +@@ -197,33 +197,31 @@ callRPC(char * user_agent, + + /* The caller is responsible for unbinding the connection if ld is not NULL */ + static LDAP * +-connect_ldap(const char *hostname, const char *binddn, const char *bindpw) { ++connect_ldap(const char *hostname, const char *binddn, const char *bindpw, ++ int *ret) { + LDAP *ld = NULL; +- int ret; +- int ldapdebug = 0; +- char *uri; ++ int ldapdebug = 2; ++ char *uri = NULL; + struct berval bindpw_bv; + +- if (debug) { +- ldapdebug = 2; +- ret = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldapdebug); +- if (ret != LDAP_OPT_SUCCESS) { +- goto fail; +- } ++ *ret = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldapdebug); ++ if (*ret != LDAP_OPT_SUCCESS) { ++ goto fail; + } + +- ret = asprintf(&uri, "ldaps://%s:636", hostname); +- if (ret == -1) { ++ *ret = asprintf(&uri, "ldaps://%s:636", hostname); ++ if (*ret == -1) { + fprintf(stderr, _("Out of memory!")); ++ *ret = LDAP_NO_MEMORY; + goto fail; + } + +- ret = ipa_ldap_init(&ld, uri); +- if (ret != LDAP_SUCCESS) { ++ *ret = ipa_ldap_init(&ld, uri); ++ if (*ret != LDAP_SUCCESS) { + goto fail; + } +- ret = ipa_tls_ssl_init(ld, uri, DEFAULT_CA_CERT_FILE); +- if (ret != LDAP_SUCCESS) { ++ *ret = ipa_tls_ssl_init(ld, uri, DEFAULT_CA_CERT_FILE); ++ if (*ret != LDAP_SUCCESS) { + fprintf(stderr, _("Unable to enable SSL in LDAP\n")); + goto fail; + } +@@ -238,15 +236,11 @@ connect_ldap(const char *hostname, const char *binddn, const char *bindpw) { + bindpw_bv.bv_len = 0; + } + +- ret = ldap_sasl_bind_s(ld, binddn, LDAP_SASL_SIMPLE, &bindpw_bv, +- NULL, NULL, NULL); +- +- if (ret != LDAP_SUCCESS) { +- int err; ++ *ret = ldap_sasl_bind_s(ld, binddn, LDAP_SASL_SIMPLE, &bindpw_bv, ++ NULL, NULL, NULL); + +- ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &err); +- if (debug) +- fprintf(stderr, _("Bind failed: %s\n"), ldap_err2string(err)); ++ if (*ret != LDAP_SUCCESS) { ++ fprintf(stderr, _("Bind failed: %s\n"), ldap_err2string(*ret)); + goto fail; + } + +@@ -309,7 +303,7 @@ get_root_dn(const char *ipaserver, char **ldap_base) + struct berval **defvals; + int ret, rval = 0; + +- ld = connect_ldap(ipaserver, NULL, NULL); ++ ld = connect_ldap(ipaserver, NULL, NULL, &ret); + if (!ld) { + rval = 14; + goto done; +@@ -429,11 +423,23 @@ join_ldap(const char *ipaserver, char *hostname, char ** binddn, const char *bin + rval = 3; + goto done; + } +- ld = connect_ldap(ipaserver, *binddn, bindpw); ++ ld = connect_ldap(ipaserver, *binddn, bindpw, &ret); + if (!ld) { +- if (!quiet) +- fprintf(stderr, _("Incorrect password.\n")); +- rval = 15; ++ if (quiet) ++ goto done; ++ ++ switch(ret) { ++ case LDAP_NO_MEMORY: ++ rval = 3; ++ break; ++ case LDAP_INVALID_CREDENTIALS: /* incorrect password */ ++ case LDAP_INAPPROPRIATE_AUTH: /* no password set */ ++ rval = 15; ++ break; ++ default: /* LDAP connection error catch-all */ ++ rval = 14; ++ break; ++ } + goto done; + } + diff --git a/SOURCES/0021-rpc_always_read_response_rhbz#1639890.patch b/SOURCES/0021-rpc_always_read_response_rhbz#1639890.patch new file mode 100644 index 0000000..627d233 --- /dev/null +++ b/SOURCES/0021-rpc_always_read_response_rhbz#1639890.patch @@ -0,0 +1,58 @@ +From 4c0e7d69e461a28a254e7c7a27c2768be3163a3d Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Wed, 7 Nov 2018 17:06:47 +1100 +Subject: [PATCH] rpc: always read response + +If the server responds 401 and the response body is empty, the +client raises ResponseNotReady. This occurs because: + +1. For a non-200 response, the response read only if the + Content-Length header occurs. + +2. The response must be read before another request (e.g. the + follow-up request with WWW-Authenticate header set), and this + condition was not met. For details see + https://github.com/python/cpython/blob/v3.6.7/Lib/http/client.py#L1305-L1321. + +This situation should not arise in regular use, because the client +either has a session cookie, or, knowing the details of the server +it is contacting, it establishes the GSS-API context and includes +the WWW-Authenticate header in the initial request. + +Nevertheless, this problem has been observed in the wild. I do not +know its ordinary cause(s), but one can force the issue by removing +an authenticated user's session cache from /run/ipa/ccaches, then +performing a request. + +Resolve the issue by always reading the response. It is safe to +call response.read() regardless of whether the Content-Length header +appears, or whether the body is empty. + +Fixes: https://pagure.io/freeipa/issue/7752 +Reviewed-By: Christian Heimes +--- + ipalib/rpc.py | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index b27f3cef9c..23841d0a4c 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -712,8 +712,15 @@ def single_request(self, host, handler, request_body, verbose=0): + response = h.getresponse() + + if response.status != 200: +- if (response.getheader("content-length", 0)): +- response.read() ++ # Must read response (even if it is empty) ++ # before sending another request. ++ # ++ # https://docs.python.org/3/library/http.client.html ++ # #http.client.HTTPConnection.getresponse ++ # ++ # https://pagure.io/freeipa/issue/7752 ++ # ++ response.read() + + if response.status == 401: + if not self._auth_complete(response): diff --git a/SOURCES/0022-ipa_vault-retrieve_fix_internal_error_rhbz#1658485.patch b/SOURCES/0022-ipa_vault-retrieve_fix_internal_error_rhbz#1658485.patch new file mode 100644 index 0000000..16ea8b9 --- /dev/null +++ b/SOURCES/0022-ipa_vault-retrieve_fix_internal_error_rhbz#1658485.patch @@ -0,0 +1,136 @@ +From 858859187a1353cbaa893642cc7b27f9f644b18b Mon Sep 17 00:00:00 2001 +From: François Cami +Date: Nov 23 2018 09:54:46 +0000 +Subject: Add a shared-vault-retrieve test + + +Add a shared-vault-retrieve test when: +* master has KRA installed +* replica has no KRA +This currently fails because of issue#7691 + +Related-to: https://pagure.io/freeipa/issue/7691 +Signed-off-by: François Cami +Reviewed-By: Christian Heimes + +--- + +diff --git a/ipatests/test_integration/test_vault.py b/ipatests/test_integration/test_vault.py +index ea2591b..e5b3ad1 100644 +--- a/ipatests/test_integration/test_vault.py ++++ b/ipatests/test_integration/test_vault.py +@@ -20,14 +20,17 @@ class TestInstallKRA(IntegrationTest): + + vault_password = "password" + vault_data = "SSBsb3ZlIENJIHRlc3RzCg==" ++ vault_user = "vault_user" ++ vault_user_password = "vault_user_password" + vault_name_master = "ci_test_vault_master" + vault_name_master2 = "ci_test_vault_master2" + vault_name_master3 = "ci_test_vault_master3" + vault_name_replica_without_KRA = "ci_test_vault_replica_without_kra" ++ shared_vault_name_replica_without_KRA = ("ci_test_shared" ++ "_vault_replica_without_kra") + vault_name_replica_with_KRA = "ci_test_vault_replica_with_kra" + vault_name_replica_KRA_uninstalled = "ci_test_vault_replica_KRA_uninstalled" + +- + @classmethod + def install(cls, mh): + tasks.install_master(cls.master, setup_kra=True) +@@ -89,6 +92,66 @@ class TestInstallKRA(IntegrationTest): + + self._retrieve_secret([self.vault_name_replica_without_KRA]) + ++ def test_create_and_retrieve_shared_vault_replica_without_kra(self): ++ # create vault ++ self.replicas[0].run_command([ ++ "ipa", "vault-add", ++ self.shared_vault_name_replica_without_KRA, ++ "--shared", ++ "--type", "standard", ++ ]) ++ ++ # archive secret ++ self.replicas[0].run_command([ ++ "ipa", "vault-archive", ++ self.shared_vault_name_replica_without_KRA, ++ "--shared", ++ "--data", self.vault_data, ++ ]) ++ time.sleep(WAIT_AFTER_ARCHIVE) ++ ++ # add non-admin user ++ self.replicas[0].run_command([ ++ 'ipa', 'user-add', self.vault_user, ++ '--first', self.vault_user, ++ '--last', self.vault_user, ++ '--password'], ++ stdin_text=self.vault_user_password) ++ ++ # add it to vault ++ self.replicas[0].run_command([ ++ "ipa", "vault-add-member", ++ self.shared_vault_name_replica_without_KRA, ++ "--shared", ++ "--users", self.vault_user, ++ ]) ++ ++ self.replicas[0].run_command([ ++ 'kdestroy', '-A']) ++ ++ user_kinit = "%s\n%s\n%s\n" % (self.vault_user_password, ++ self.vault_user_password, ++ self.vault_user_password) ++ ++ self.replicas[0].run_command([ ++ 'kinit', self.vault_user], ++ stdin_text=user_kinit) ++ ++ # TODO: possibly refactor with: ++ # self._retrieve_secret([self.vault_name_replica_without_KRA]) ++ ++ self.replicas[0].run_command([ ++ "ipa", "vault-retrieve", ++ "--shared", ++ self.shared_vault_name_replica_without_KRA, ++ "--out=test.txt"]) ++ ++ self.replicas[0].run_command([ ++ 'kdestroy', '-A']) ++ ++ tasks.kinit_admin(self.replicas[0]) ++ ++ + def test_create_and_retrieve_vault_replica_with_kra(self): + + # install KRA on replica + +From d57d97ea7f911e18ac75d532e19833c4efaafa96 Mon Sep 17 00:00:00 2001 +From: François Cami +Date: Nov 23 2018 09:54:46 +0000 +Subject: Add a "Find enabled services" ACI in 20-aci.update so that all users can find IPA servers and services. ACI suggested by Christian Heimes. + + +Fixes: https://pagure.io/freeipa/issue/7691 +Signed-off-by: François Cami +Reviewed-By: Christian Heimes + +--- + +diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update +index 184749d..7650cb4 100644 +--- a/install/updates/20-aci.update ++++ b/install/updates/20-aci.update +@@ -36,6 +36,10 @@ remove:aci:(targetfilter="(objectclass=nsContainer)")(version 3.0; acl "Deny rea + dn: cn=masters,cn=ipa,cn=etc,$SUFFIX + add:aci:(targetfilter="(objectclass=nsContainer)")(targetattr="objectclass || cn")(version 3.0; acl "Read access to masters"; allow(read, search, compare) userdn = "ldap:///all";) + ++# Allow users to discover enabled services ++dn: cn=masters,cn=ipa,cn=etc,$SUFFIX ++add:aci:(targetfilter = "(ipaConfigString=enabledService)")(targetattrs = "ipaConfigString")(version 3.0; acl "Find enabled services"; allow(read, search, compare) userdn = "ldap:///all";) ++ + # Allow hosts to read masters service configuration + dn: cn=masters,cn=ipa,cn=etc,$SUFFIX + add:aci:(targetfilter = "(objectclass=nsContainer)")(targetattr = "ipaConfigString")(version 3.0; acl "Allow hosts to read masters service configuration"; allow(read, search, compare) userdn = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX";) + diff --git a/SOURCES/0023-Move_ipa_s_systemd_tmpfiles_from_var_run_to_run_rhbz#1658487.patch b/SOURCES/0023-Move_ipa_s_systemd_tmpfiles_from_var_run_to_run_rhbz#1658487.patch new file mode 100644 index 0000000..d4ec1e8 --- /dev/null +++ b/SOURCES/0023-Move_ipa_s_systemd_tmpfiles_from_var_run_to_run_rhbz#1658487.patch @@ -0,0 +1,47 @@ +From 13b6fec04582d43bfc057a4cc3dbb7e652c8a64f Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Oct 15 2018 12:07:12 +0000 +Subject: Move ipa's systemd tmpfiles from /var/run to /run + + +systemd 239 complains about the legacy of ipa's tmpfiles which +are located on /var/run. + +Fixes: https://pagure.io/freeipa/issue/7732 +Reviewed-By: Christian Heimes + +--- + +diff --git a/init/tmpfilesd/Makefile.am b/init/tmpfilesd/Makefile.am +index b2d91c3..3ea4533 100644 +--- a/init/tmpfilesd/Makefile.am ++++ b/init/tmpfilesd/Makefile.am +@@ -7,4 +7,4 @@ systemdtmpfiles_DATA = \ + CLEANFILES = $(systemdtmpfiles_DATA) + + %: %.in Makefile +- sed -e 's|@localstatedir[@]|$(localstatedir)|g' '$(srcdir)/$@.in' >$@ ++ cp '$(srcdir)/$@.in' $@ +diff --git a/init/tmpfilesd/ipa.conf.in b/init/tmpfilesd/ipa.conf.in +index df66bef..183ceed 100644 +--- a/init/tmpfilesd/ipa.conf.in ++++ b/init/tmpfilesd/ipa.conf.in +@@ -1,2 +1,2 @@ +-d @localstatedir@/run/ipa 0711 root root +-d @localstatedir@/run/ipa/ccaches 0770 ipaapi ipaapi ++d /run/ipa 0711 root root ++d /run/ipa/ccaches 0770 ipaapi ipaapi +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index bc04964..8c1d44f 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -350,7 +350,7 @@ class BasePathNamespace(object): + OPENDNSSEC_KASP_DB = "/var/opendnssec/kasp.db" + IPA_ODS_EXPORTER_CCACHE = "/var/opendnssec/tmp/ipa-ods-exporter.ccache" + VAR_RUN_DIRSRV_DIR = "/var/run/dirsrv" +- IPA_CCACHES = "/var/run/ipa/ccaches" ++ IPA_CCACHES = "/run/ipa/ccaches" + HTTP_CCACHE = "/var/lib/ipa/gssproxy/http.ccache" + CA_BUNDLE_PEM = "/var/lib/ipa-client/pki/ca-bundle.pem" + KDC_CA_BUNDLE_PEM = "/var/lib/ipa-client/pki/kdc-ca-bundle.pem" + diff --git a/SOURCES/0024-Fix_authselect_invocations_to_work_with_1.0.2_rhbz#1654291.patch b/SOURCES/0024-Fix_authselect_invocations_to_work_with_1.0.2_rhbz#1654291.patch new file mode 100644 index 0000000..63c6f05 --- /dev/null +++ b/SOURCES/0024-Fix_authselect_invocations_to_work_with_1.0.2_rhbz#1654291.patch @@ -0,0 +1,78 @@ +From 05c5be1b1c5ae63c5547d248d926b3411bff2733 Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Nov 29 2018 15:58:38 +0000 +Subject: Fix authselect invocations to work with 1.0.2 + + +Since authselect 1.0.2, invoking an authselect command sequence +like this: + +['authselect', 'sssd', '', '--force'] + +does not work: authselect barfs on the empty string arg and +errors out. We must only pass a features arg if we actually have +some text to go in it. + +This broke uninstallation. + +In all cases, features are now passed as separate arguments instead of one +argument separated by space. + +Fixes: https://pagure.io/freeipa/issue/7776 +Signed-off-by: Adam Williamson +Reviewed-By: Alexander Bokovoy + +--- + +diff --git a/ipaplatform/redhat/authconfig.py b/ipaplatform/redhat/authconfig.py +index 77ccc36..58cf7df 100644 +--- a/ipaplatform/redhat/authconfig.py ++++ b/ipaplatform/redhat/authconfig.py +@@ -158,15 +158,26 @@ class RedHatAuthSelect(RedHatAuthToolBase): + " ".join(args)) + + profile = 'sssd' +- features = '' ++ features = [] + else: +- profile = \ +- statestore.restore_state('authselect', 'profile') or 'sssd' +- features = \ +- statestore.restore_state('authselect', 'features_list') or '' ++ profile = statestore.restore_state('authselect', 'profile') ++ if not profile: ++ profile = 'sssd' ++ features_state = statestore.restore_state( ++ 'authselect', 'features_list' ++ ) + statestore.delete_state('authselect', 'mkhomedir') ++ # only non-empty features, https://pagure.io/freeipa/issue/7776 ++ if features_state is not None: ++ features = [ ++ f.strip() for f in features_state.split(' ') if f.strip() ++ ] ++ else: ++ features = [] + +- cmd = [paths.AUTHSELECT, "select", profile, features, "--force"] ++ cmd = [paths.AUTHSELECT, "select", profile] ++ cmd.extend(features) ++ cmd.append("--force") + ipautil.run(cmd) + + def backup(self, path): +@@ -186,10 +197,9 @@ class RedHatAuthSelect(RedHatAuthToolBase): + + if cfg: + profile = cfg[0] +- +- cmd = [ +- paths.AUTHSELECT, "select", profile, +- " ".join(cfg[1]), "--force"] ++ cmd = [paths.AUTHSELECT, "select", profile] ++ cmd.extend(cfg[1]) ++ cmd.append("--force") + ipautil.run(cmd) + + def set_nisdomain(self, nisdomain): + diff --git a/SOURCES/0025-ipa-client-automount_and_NFS_unit_name_changes_rhbz#1645501.patch b/SOURCES/0025-ipa-client-automount_and_NFS_unit_name_changes_rhbz#1645501.patch new file mode 100644 index 0000000..935d25d --- /dev/null +++ b/SOURCES/0025-ipa-client-automount_and_NFS_unit_name_changes_rhbz#1645501.patch @@ -0,0 +1,291 @@ +From 65f6c8dc2585144b17ff89e63e4ba300971996dd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= +Date: Thu, 6 Dec 2018 16:10:00 +0100 +Subject: [PATCH] Fix NFS unit names +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +NFS unit names were renamed. +Compatibility was maintained with older unit names +through symlinks. When these symlinks are removed +only new unit names work, so changing to using non- +symlink unit names is required. + +Fixes: https://pagure.io/freeipa/issue/7783 +Signed-off-by: François Cami +Reviewed-By: Alexander Bokovoy +--- + ipaplatform/redhat/services.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaplatform/redhat/services.py b/ipaplatform/redhat/services.py +index 390bbb0231..20395aee44 100644 +--- a/ipaplatform/redhat/services.py ++++ b/ipaplatform/redhat/services.py +@@ -45,8 +45,8 @@ + redhat_system_units = dict((x, "%s.service" % x) + for x in base_services.wellknownservices) + +-redhat_system_units['rpcgssd'] = 'nfs-secure.service' +-redhat_system_units['rpcidmapd'] = 'nfs-idmap.service' ++redhat_system_units['rpcgssd'] = 'rpc-gssd.service' ++redhat_system_units['rpcidmapd'] = 'nfs-idmapd.service' + redhat_system_units['domainname'] = 'nis-domainname.service' + + # Rewrite dirsrv and pki-tomcatd services as they support instances via separate +From 0687e4869995842a90d5d656749de42daceb2ad4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= +Date: Thu, 6 Dec 2018 17:29:26 +0100 +Subject: [PATCH] ipa-client-automount: use nfs-utils unit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +- remove nfs-idmapd from units we enable & start as: + - it is not used on NFS clients anymore + - it is a static unit +- remove rpc-gssd as well as it is a static unit +- restart nfs-utils and rpc-gssd +- manage systemctl-related exceptions during uninstall + +Fixes: https://pagure.io/freeipa/issue/7780 +Fixes: https://pagure.io/freeipa/issue/7781 +Signed-off-by: François Cami +Reviewed-By: Alexander Bokovoy +--- + client/ipa-client-automount.in | 55 +++++++++++----------------------- + ipaplatform/base/services.py | 3 +- + 2 files changed, 20 insertions(+), 38 deletions(-) + mode change 100644 => 100755 client/ipa-client-automount.in + +diff --git a/client/ipa-client-automount.in b/client/ipa-client-automount.in +old mode 100644 +new mode 100755 +index 7348e20775..15926bd028 +--- a/client/ipa-client-automount.in ++++ b/client/ipa-client-automount.in +@@ -314,23 +314,21 @@ def uninstall(fstore, statestore): + print('Unable to restore SSSD configuration: %s' % str(e)) + logger.debug('Unable to restore SSSD configuration: %s', + str(e)) ++ ++ # rpcidmapd and rpcgssd are static units now + if statestore.has_state('rpcidmapd'): +- enabled = statestore.restore_state('rpcidmapd', 'enabled') +- running = statestore.restore_state('rpcidmapd', 'running') +- rpcidmapd = services.knownservices.rpcidmapd +- if not enabled: +- rpcidmapd.disable() +- if not running: +- rpcidmapd.stop() ++ statestore.delete_state('rpcidmapd','enabled') ++ statestore.delete_state('rpcidmapd','running') + if statestore.has_state('rpcgssd'): +- enabled = statestore.restore_state('rpcgssd', 'enabled') +- running = statestore.restore_state('rpcgssd', 'running') +- rpcgssd = services.knownservices.rpcgssd +- if not enabled: +- rpcgssd.disable() +- if not running: +- rpcgssd.stop() ++ statestore.delete_state('rpcgssd','enabled') ++ statestore.delete_state('rpcgssd','running') + ++ nfsutils = services.knownservices['nfs-utils'] ++ try: ++ nfsutils.restart() ++ except Exception as e: ++ logger.error("Failed to restart nfs client services (%s)" % str(e)) ++ return 1 + return 0 + + def configure_nfs(fstore, statestore): +@@ -365,35 +363,18 @@ def configure_nfs(fstore, statestore): + + print("Configured %s" % paths.IDMAPD_CONF) + +- rpcidmapd = services.knownservices.rpcidmapd +- statestore.backup_state('rpcidmapd', 'enabled', rpcidmapd.is_enabled()) +- statestore.backup_state('rpcidmapd', 'running', rpcidmapd.is_running()) +- try: +- rpcidmapd.restart() +- print("Started %s" % rpcidmapd.service_name) +- except Exception as e: +- logger.error("%s failed to restart: %s", rpcidmapd.service_name, e) +- try: +- rpcidmapd.enable() +- except Exception as e: +- print("Failed to configure automatic startup of the %s daemon" % (rpcidmapd.service_name)) +- logger.error("Failed to enable automatic startup of the %s daemon: %s", +- rpcidmapd.service_name, str(e)) +- + rpcgssd = services.knownservices.rpcgssd +- statestore.backup_state('rpcgssd', 'enabled', rpcgssd.is_enabled()) +- statestore.backup_state('rpcgssd', 'running', rpcgssd.is_running()) + try: + rpcgssd.restart() +- print("Started %s" % rpcgssd.service_name) + except Exception as e: +- logger.error("%s failed to restart: %s", rpcgssd.service_name, e) ++ logger.error("Failed to restart rpc-gssd (%s)" % str(e)) ++ return 1 ++ nfsutils = services.knownservices['nfs-utils'] + try: +- rpcgssd.enable() ++ nfsutils.restart() + except Exception as e: +- print("Failed to configure automatic startup of the %s daemon" % (rpcgssd.service_name)) +- logger.error("Failed to enable automatic startup of the %s daemon: %s", +- rpcgssd.service_name, str(e)) ++ logger.error("Failed to restart nfs client services (%s)" % str(e)) ++ return 1 + + def main(): + try: +diff --git a/ipaplatform/base/services.py b/ipaplatform/base/services.py +index 4533ad5b34..51c27848d7 100644 +--- a/ipaplatform/base/services.py ++++ b/ipaplatform/base/services.py +@@ -53,7 +53,8 @@ + 'dbus', 'nslcd', 'nscd', 'ntpd', 'portmap', + 'rpcbind', 'kadmin', 'sshd', 'autofs', 'rpcgssd', + 'rpcidmapd', 'pki_tomcatd', 'chronyd', 'domainname', +- 'named', 'ods_enforcerd', 'ods_signerd', 'gssproxy'] ++ 'named', 'ods_enforcerd', 'ods_signerd', 'gssproxy', ++ 'nfs-utils'] + + # The common ports for these services. This is used to wait for the + # service to become available. +From dfd741d3cd9c9d695e7ad6f88dcd4432fb73c126 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= +Date: Mon, 10 Dec 2018 17:12:03 +0100 +Subject: [PATCH] ipatests: add a test for ipa-client-automount +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add an automount location then configure a client +to use it. Only runs nightly. + +Related-to: https://pagure.io/freeipa/issue/7780 +Related-to: https://pagure.io/freeipa/issue/7781 +Related to: https://pagure.io/freeipa/issue/7783 +Signed-off-by: François Cami +Reviewed-By: Alexander Bokovoy +--- + ipatests/prci_definitions/nightly_master.yaml | 12 +++ + .../test_automount_locations.py | 84 +++++++++++++++++++ + 2 files changed, 96 insertions(+) + create mode 100644 ipatests/test_integration/test_automount_locations.py + +diff --git a/ipatests/prci_definitions/nightly_master.yaml b/ipatests/prci_definitions/nightly_master.yaml +index 154e4c945d..b4dcc0870e 100644 +--- a/ipatests/prci_definitions/nightly_master.yaml ++++ b/ipatests/prci_definitions/nightly_master.yaml +@@ -663,3 +663,15 @@ jobs: + template: *ci-master-f29 + timeout: 3600 + topology: *master_1repl ++ ++ fedora-29/test_automount_locations: ++ requires: [fedora-29/build] ++ priority: 50 ++ job: ++ class: RunPytest ++ args: ++ build_url: '{fedora-29/build_url}' ++ test_suite: test_integration/test_automount_locations.py ++ template: *ci-master-f29 ++ timeout: 6300 ++ topology: *master_1repl +diff --git a/ipatests/test_integration/test_automount_locations.py b/ipatests/test_integration/test_automount_locations.py +new file mode 100644 +index 0000000000..646d1d07a0 +--- /dev/null ++++ b/ipatests/test_integration/test_automount_locations.py +@@ -0,0 +1,84 @@ ++# ++# Copyright (C) 2018 FreeIPA Contributors see COPYING for license ++# ++ ++"""This module provides tests for the automount location feature. ++""" ++ ++from __future__ import absolute_import ++ ++import time ++import re ++ ++from ipatests.test_integration.base import IntegrationTest ++from ipatests.pytest_ipa.integration import tasks ++ ++# give some time for units to stabilize ++# otherwise we get transient errors ++WAIT_AFTER_INSTALL = 5 ++WAIT_AFTER_UNINSTALL = WAIT_AFTER_INSTALL ++ ++ ++class TestAutomountInstallUninstall(IntegrationTest): ++ """ ++ Test if ipa-client-automount behaves as expected ++ """ ++ ++ num_replicas = 1 ++ topology = 'star' ++ ++ @classmethod ++ def install(cls, mh): ++ tasks.install_master(cls.master, setup_dns=False) ++ client = cls.replicas[0] ++ tasks.install_client(cls.master, client) ++ ++ def test_use_automount_location(self): ++ ++ client = self.replicas[0] ++ ++ self.master.run_command([ ++ "ipa", "automountlocation-add", "baltimore" ++ ]) ++ ++ self.master.run_command([ ++ "ipa", "host-mod", client.hostname, ++ "--location", "baltimore" ++ ]) ++ ++ # systemctl non-fatal errors will only be displayed ++ # if ipa-client-automount is launched with --debug ++ result1 = client.run_command([ ++ 'ipa-client-automount', '--location', 'baltimore', ++ '-U', '--debug' ++ ]) ++ ++ # systemctl non-fatal errors will show up like this: ++ # stderr=Failed to restart nfs-secure.service: \ ++ # Unit nfs-secure.service not found. ++ # normal output: ++ # stderr= ++ m1 = re.search(r'(?<=stderr\=Failed).+', result1.stderr_text) ++ # maybe re-use m1.group(0) if it exists. ++ assert m1 is None ++ ++ time.sleep(WAIT_AFTER_INSTALL) ++ ++ result2 = client.run_command([ ++ 'ipa-client-automount', '--uninstall', ++ '-U', '--debug' ++ ]) ++ ++ m2 = re.search(r'(?<=stderr\=Failed).+', result2.stderr_text) ++ assert m2 is None ++ ++ time.sleep(WAIT_AFTER_UNINSTALL) ++ ++ self.master.run_command([ ++ "ipa", "host-mod", client.hostname, ++ "--location", "''" ++ ]) ++ ++ self.master.run_command([ ++ "ipa", "automountlocation-del", "baltimore" ++ ]) diff --git a/SOURCES/0026-Fix_compile_issue_with_new_389-ds_rhbz#1659448.patch b/SOURCES/0026-Fix_compile_issue_with_new_389-ds_rhbz#1659448.patch new file mode 100644 index 0000000..640a3dd --- /dev/null +++ b/SOURCES/0026-Fix_compile_issue_with_new_389-ds_rhbz#1659448.patch @@ -0,0 +1,51 @@ +From 2b30b637561eb56a1fb73164322c9a74c8365c0b Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 14 Dec 2018 14:02:26 +0200 +Subject: [PATCH] ipa-sidgen: make internal fetch_attr helper really internal + +With 389-ds landing a change for +https://pagure.io/389-ds-base/issue/49950, fetch_attr() helper function +is exposed in slapi-plugin.h. However, in order to be able to build +FreeIPA plugins against older 389-ds versions, prefer using a local +variant of it. + +Rename fetch_attr() to ipa_sidgen_fetch_attr() so that it doesn't +conflict at all. + +Fixes: https://pagure.io/freeipa/issue/7811 +Reviewed-By: Christian Heimes +--- + daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c +index 9e474e83dd..007b1c945d 100644 +--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c ++++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_task.c +@@ -63,7 +63,7 @@ struct worker_ctx { + struct range_info **ranges; + }; + +-static const char *fetch_attr(Slapi_Entry *e, const char *attrname, ++static const char *ipa_sidgen_fetch_attr(Slapi_Entry *e, const char *attrname, + const char *default_val) + { + Slapi_Attr *attr; +@@ -242,7 +242,7 @@ int sidgen_task_add(Slapi_PBlock *pb, Slapi_Entry *e, + + worker_ctx->plugin_id = global_sidgen_plugin_id; + +- str = fetch_attr(e, "delay", NULL); ++ str = ipa_sidgen_fetch_attr(e, "delay", NULL); + if (str != NULL) { + errno = 0; + worker_ctx->delay = strtol(str, &endptr, 10); +@@ -255,7 +255,7 @@ int sidgen_task_add(Slapi_PBlock *pb, Slapi_Entry *e, + } + LOG("delay is [%li].\n", worker_ctx->delay); + +- str = fetch_attr(e, "nsslapd-basedn", NULL); ++ str = ipa_sidgen_fetch_attr(e, "nsslapd-basedn", NULL); + if (str == NULL) { + LOG_FATAL("Missing nsslapd-basedn!\n"); + *returncode = LDAP_CONSTRAINT_VIOLATION; diff --git a/SOURCES/0027-ipaserver-dcerpc-fix-exclusion-entry-with-a-forest-t.patch b/SOURCES/0027-ipaserver-dcerpc-fix-exclusion-entry-with-a-forest-t.patch new file mode 100644 index 0000000..50cc957 --- /dev/null +++ b/SOURCES/0027-ipaserver-dcerpc-fix-exclusion-entry-with-a-forest-t.patch @@ -0,0 +1,166 @@ +From e5471e66c6a718ffa28433813b8a8d7896b16d9e Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 7 Jan 2019 15:28:29 +0200 +Subject: [PATCH] ipaserver/dcerpc: fix exclusion entry with a forest trust + domain info returned + +When looking through the topology of a trusted forest, we should support +all types of forest trust records. Since Samba Python bindings parse the +data into a typed structure, a type of the record has to be taken into +account or there will be type mismatch when accessing elements of the +union: + + typedef [switch_type(lsa_ForestTrustRecordType)] union { + [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME)] lsa_StringLarge top_level_name; + [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX)] lsa_StringLarge top_level_name_ex; + [case(LSA_FOREST_TRUST_DOMAIN_INFO)] lsa_ForestTrustDomainInfo domain_info; + [default] lsa_ForestTrustBinaryData data; + } lsa_ForestTrustData; + + typedef struct { + lsa_ForestTrustRecordFlags flags; + lsa_ForestTrustRecordType type; + NTTIME_hyper time; + [switch_is(type)] lsa_ForestTrustData forest_trust_data; + } lsa_ForestTrustRecord; + + typedef [public] struct { + [range(0,4000)] uint32 count; + [size_is(count)] lsa_ForestTrustRecord **entries; + } lsa_ForestTrustInformation; + +Each entry in the lsa_ForestTrustInformation has forest_trust_data +member but its content depends on the value of a type member +(forest_trust_data is a union of all possible structures). + +Previously we assumed only TLN or TLN exclusion record which were +of the same type (lsa_StringLarge). Access to forest_trust_data.string +fails when forest_trust_data's type is lsa_ForestTrustDomainInfo as it +has no string member. + +Fix the code by properly accessing the dns_domain_name from the +lsa_ForestTrustDomainInfo structure. + +Fixes: https://pagure.io/freeipa/issue/7828 +Reviewed-By: Christian Heimes +--- + ipaserver/dcerpc.py | 64 ++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 55 insertions(+), 9 deletions(-) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index 125493657..51a8e82e7 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -51,6 +51,7 @@ from samba.dcerpc import security, lsa, drsblobs, nbt, netlogon + from samba.ndr import ndr_pack, ndr_print + from samba import net + from samba import arcfour_encrypt ++from samba import ntstatus + import samba + + import ldap as _ldap +@@ -1105,6 +1106,25 @@ class TrustDomainInstance(object): + original forest. + """ + ++ def domain_name_from_ftinfo(ftinfo): ++ """ ++ Returns a domain name string from a ForestTrustRecord ++ ++ :param ftinfo: LSA ForestTrustRecord to parse ++ """ ++ if ftinfo.type == lsa.LSA_FOREST_TRUST_DOMAIN_INFO: ++ return ftinfo.forest_trust_data.dns_domain_name.string ++ elif ftinfo.type == lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME: ++ return ftinfo.forest_trust_data.string ++ elif ftinfo.type == lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: ++ # We should ignore TLN exclusion record because it ++ # is already an exclusion so we aren't going to ++ # change anything here ++ return None ++ else: ++ # Ignore binary blobs we don't know about ++ return None ++ + # List of entries for unsolved conflicts + result = [] + +@@ -1145,18 +1165,26 @@ class TrustDomainInstance(object): + e1.time = e.time + e1.forest_trust_data = e.forest_trust_data + ++ # We either have a domain struct, a TLN name, ++ # or a TLN exclusion name in the list. ++ # The rest we should skip, those are binary blobs ++ dns_domain_name = domain_name_from_ftinfo(e) ++ + # Search for a match in the topology of another domain + # if there is a match, we have to convert a record + # into a TLN exclusion to allow its routing to the + # another domain + for r in another_domain.ftinfo_records: +- if r['rec_name'] == e.forest_trust_data.string: ++ # r['rec_name'] cannot be None, thus we can ignore ++ # the case when dns_domain_name is None ++ if r['rec_name'] == dns_domain_name: + is_our_record = True + + # Convert e1 into an exclusion record + e1.type = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX + e1.flags = 0 + e1.time = trust_timestamp ++ e1.forest_trust_data.string = dns_domain_name + break + entries.append(e1) + +@@ -1180,11 +1208,29 @@ class TrustDomainInstance(object): + # Update the forest trust information now + ldname = lsa.StringLarge() + ldname.string = rec.name.string +- cninfo = self._pipe.lsaRSetForestTrustInformation( +- self._policy_handle, +- ldname, +- lsa.LSA_FOREST_TRUST_DOMAIN_INFO, +- fti, 0) ++ cninfo = None ++ try: ++ cninfo = self._pipe.lsaRSetForestTrustInformation( ++ self._policy_handle, ++ ldname, ++ lsa.LSA_FOREST_TRUST_DOMAIN_INFO, ++ fti, 0) ++ except samba.NTSTATUSError as error: ++ # Handle NT_STATUS_INVALID_PARAMETER separately ++ if ntstatus.NT_STATUS_INVALID_PARAMETER == error.args[0]: ++ result.append(rec) ++ logger.error("Unable to resolve conflict for " ++ "DNS domain %s in the forest %s " ++ "for in-forest domain %s. Trust cannot " ++ "be established unless this conflict " ++ "is fixed manually.", ++ another_domain.info['dns_domain'], ++ self.info['dns_domain'], ++ rec.name.string) ++ else: ++ raise assess_dcerpc_error(error) ++ ++ + if cninfo: + result.append(rec) + logger.error("When defining exception for DNS " +@@ -1213,9 +1259,9 @@ class TrustDomainInstance(object): + # Otherwise, raise TrustTopologyConflictError() exception + domains = [x.name.string for x in result] + raise errors.TrustTopologyConflictError( +- target=self.info['dns_domain'], +- conflict=another_domain.info['dns_domain'], +- domains=domains) ++ forest=self.info['dns_domain'], ++ conflict=another_domain.info['dns_domain'], ++ domains=domains) + + + +-- +2.20.1 + diff --git a/SOURCES/0028-Create-systemd-user-HBAC-service-and-rule.patch b/SOURCES/0028-Create-systemd-user-HBAC-service-and-rule.patch new file mode 100644 index 0000000..188d163 --- /dev/null +++ b/SOURCES/0028-Create-systemd-user-HBAC-service-and-rule.patch @@ -0,0 +1,191 @@ +From aaf938307acbe987f5e1effc2392894c22235013 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 11 Jan 2019 11:18:05 +0100 +Subject: [PATCH] Create systemd-user HBAC service and rule + +authselect changed pam_systemd session from optional to required. When +the HBAC rule allow_all is disabled and replaced with more fine grained +rules, loginsi now to fail, because systemd's user@.service is able to +create a systemd session. + +Add systemd-user HBAC service and a HBAC rule that allows systemd-user +to run on all hosts for all users by default. ipa-server-upgrade creates +the service and rule, too. In case the service already exists, no +attempt is made to create the rule. This allows admins to delete the +rule permanently. + +See: https://bugzilla.redhat.com/show_bug.cgi?id=1643928 +Fixes: https://pagure.io/freeipa/issue/7831 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + install/share/bootstrap-template.ldif | 8 +++ + install/share/default-hbac.ldif | 13 +++++ + ipaserver/install/server/upgrade.py | 36 +++++++++++++ + ipatests/test_integration/test_commands.py | 59 ++++++++++++++++++++++ + 4 files changed, 116 insertions(+) + +diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif +index d48c4fafc..6cd17e37e 100644 +--- a/install/share/bootstrap-template.ldif ++++ b/install/share/bootstrap-template.ldif +@@ -346,6 +346,14 @@ cn: sudo-i + description: sudo-i + ipauniqueid:autogenerate + ++dn: cn=systemd-user,cn=hbacservices,cn=hbac,$SUFFIX ++changetype: add ++objectclass: ipahbacservice ++objectclass: ipaobject ++cn: systemd-user ++description: pam_systemd and systemd user@.service ++ipauniqueid:autogenerate ++ + dn: cn=gdm,cn=hbacservices,cn=hbac,$SUFFIX + changetype: add + objectclass: ipahbacservice +diff --git a/install/share/default-hbac.ldif b/install/share/default-hbac.ldif +index 52fd30ec9..8dd90685c 100644 +--- a/install/share/default-hbac.ldif ++++ b/install/share/default-hbac.ldif +@@ -12,3 +12,16 @@ ipaenabledflag: TRUE + description: Allow all users to access any host from any host + ipauniqueid: autogenerate + ++# default HBAC policy for pam_systemd ++dn: ipauniqueid=autogenerate,cn=hbac,$SUFFIX ++changetype: add ++objectclass: ipaassociation ++objectclass: ipahbacrule ++cn: allow_systemd-user ++accessruletype: allow ++usercategory: all ++hostcategory: all ++servicecategory: systemd-user ++ipaenabledflag: TRUE ++description: Allow pam_systemd to run user@.service to create a system user session ++ipauniqueid: autogenerate +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index ae6fcc77e..3869bae3c 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1735,6 +1735,41 @@ def migrate_to_authselect(): + sysupgrade.set_upgrade_state('authcfg', 'migrated_to_authselect', True) + + ++def add_systemd_user_hbac(): ++ logger.info('[Create systemd-user hbac service and rule]') ++ rule = 'allow_systemd-user' ++ service = 'systemd-user' ++ try: ++ api.Command.hbacsvc_add( ++ service, ++ description='pam_systemd and systemd user@.service' ++ ) ++ except ipalib.errors.DuplicateEntry: ++ logger.info('hbac service %s already exists', service) ++ # Don't create hbac rule when hbacsvc already exists, so the rule ++ # does not get re-created after it has been deleted by an admin. ++ return ++ else: ++ logger.info('Created hbacsvc %s', service) ++ ++ try: ++ api.Command.hbacrule_add( ++ rule, ++ description=('Allow pam_systemd to run user@.service to create ' ++ 'a system user session'), ++ usercategory='all', ++ hostcategory='all', ++ ) ++ except ipalib.errors.DuplicateEntry: ++ logger.info('hbac rule %s already exists', rule) ++ else: ++ api.Command.hbacrule_add_service( ++ rule, ++ hbacsvc=(service,) ++ ) ++ logger.info('Created hbac rule %s with hbacsvc=%s', rule, service) ++ ++ + def fix_permissions(): + """Fix permission of public accessible files and directories + +@@ -2050,6 +2085,7 @@ def upgrade_configuration(): + cainstance.ensure_ipa_authority_entry() + + migrate_to_authselect() ++ add_systemd_user_hbac() + + sssd_update() + +diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py +index cfb2fa48d..1fb6450a2 100644 +--- a/ipatests/test_integration/test_commands.py ++++ b/ipatests/test_integration/test_commands.py +@@ -462,3 +462,62 @@ class TestIPACommand(IntegrationTest): + ['sudo', '-u', IPAAPI_USER, '--'] + cmd + ) + assert uid in result.stdout_text ++ ++ def test_hbac_systemd_user(self): ++ # https://pagure.io/freeipa/issue/7831 ++ tasks.kinit_admin(self.master) ++ # check for presence ++ self.master.run_command( ++ ['ipa', 'hbacrule-show', 'allow_systemd-user'] ++ ) ++ self.master.run_command( ++ ['ipa', 'hbacsvc-show', 'systemd-user'] ++ ) ++ ++ # delete both ++ self.master.run_command( ++ ['ipa', 'hbacrule-del', 'allow_systemd-user'] ++ ) ++ self.master.run_command( ++ ['ipa', 'hbacsvc-del', 'systemd-user'] ++ ) ++ ++ # run upgrade ++ result = self.master.run_command(['ipa-server-upgrade']) ++ assert 'Created hbacsvc systemd-user' in result.stderr_text ++ assert 'Created hbac rule allow_systemd-user' in result.stderr_text ++ ++ # check for presence ++ result = self.master.run_command( ++ ['ipa', 'hbacrule-show', 'allow_systemd-user', '--all'] ++ ) ++ lines = set(l.strip() for l in result.stdout_text.split('\n')) ++ assert 'User category: all' in lines ++ assert 'Host category: all' in lines ++ assert 'Enabled: TRUE' in lines ++ assert 'Services: systemd-user' in lines ++ assert 'accessruletype: allow' in lines ++ ++ self.master.run_command( ++ ['ipa', 'hbacsvc-show', 'systemd-user'] ++ ) ++ ++ # only delete rule ++ self.master.run_command( ++ ['ipa', 'hbacrule-del', 'allow_systemd-user'] ++ ) ++ ++ # run upgrade ++ result = self.master.run_command(['ipa-server-upgrade']) ++ assert ( ++ 'hbac service systemd-user already exists' in result.stderr_text ++ ) ++ assert ( ++ 'Created hbac rule allow_systemd-user' not in result.stderr_text ++ ) ++ result = self.master.run_command( ++ ['ipa', 'hbacrule-show', 'allow_systemd-user'], ++ raiseonerr=False ++ ) ++ assert result.returncode != 0 ++ assert 'HBAC rule not found' in result.stderr_text +-- +2.20.1 + diff --git a/SOURCES/0029-Resolve_user_group_names_in_idoverride_-find_rhbz#1657745.patch b/SOURCES/0029-Resolve_user_group_names_in_idoverride_-find_rhbz#1657745.patch new file mode 100644 index 0000000..9d2cda5 --- /dev/null +++ b/SOURCES/0029-Resolve_user_group_names_in_idoverride_-find_rhbz#1657745.patch @@ -0,0 +1,405 @@ +BEGIN EXCERPT from 8182ebc6c3ca636276fc277186cfbff4ea9cf5c6 to have user_add +in ipatests/pytest_ipa/integration/tasks.py to be able to apply the patch set. + +commit 8182ebc6c3ca636276fc277186cfbff4ea9cf5c6 +Author: Sergey Orlov +Date: Wed Nov 7 11:23:05 2018 +0100 + + ipatests: add test for ipa-restore in multi-master configuration + + Test ensures that after ipa-restore on the master, the replica can be + re-synchronized and a new replica can be created. + + https://pagure.io/freeipa/issue/7455 + + Reviewed-By: Christian Heimes + Reviewed-By: Tibor Dudlak + +diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py +index 814141b83..90da8fa62 100644 +--- a/ipatests/pytest_ipa/integration/tasks.py ++++ b/ipatests/pytest_ipa/integration/tasks.py +@@ -1555,3 +1561,11 @@ def strip_cert_header(pem): + return s.group(1) + else: + return pem ++ ++ ++def user_add(host, login): ++ host.run_command([ ++ "ipa", "user-add", login, ++ "--first", "test", ++ "--last", "user" ++ ]) +END EXCERPT +From 5e6cb0ca034c711fe81fcfe7c651c5af3c65aa40 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Dec 07 2018 15:06:13 +0000 +Subject: Resolve user/group names in idoverride*-find + + +ipa idoverrideuser-find and ...group-find have an --anchor argument. The +anchor argument used to support only anchor UUIDs like +':IPA:domain:UUID' or ':SID:S-sid'. The find commands now detect regular +user or group names and translate them to anchors. + +Fixes: https://pagure.io/freeipa/issue/6594 +Signed-off-by: Christian Heimes +Reviewed-By: Rob Crittenden + +--- + +diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py +index 3252982..5213486 100644 +--- a/ipaserver/plugins/idviews.py ++++ b/ipaserver/plugins/idviews.py +@@ -766,6 +766,40 @@ class baseidoverride(LDAPObject): + error=_('Default Trust View cannot contain IPA users') + ) + ++ def filter_for_anchor(self, ldap, filter, options, obj_type): ++ """Modify filter to support user and group names ++ ++ Allow users to pass in an IPA user/group name and resolve it to an ++ anchor name. ++ ++ :param ldap: ldap connection ++ :param filter: pre_callback filter ++ :param options: option dict ++ :param obj_type: 'user' or 'group' ++ :return: modified or same filter ++ """ ++ anchor = options.get('ipaanchoruuid', None) ++ # return original filter if anchor is absent or correct ++ if anchor is None or ANCHOR_REGEX.match(anchor): ++ return filter ++ try: ++ resolved_anchor = resolve_object_to_anchor( ++ ldap, obj_type, anchor, ++ options.get('fallback_to_ldap', False) ++ ) ++ except (errors.NotFound, errors.ValidationError): ++ # anchor cannot be resolved, let it pass through ++ return filter ++ else: ++ return ldap.make_filter( ++ { ++ 'objectClass': self.object_class, ++ 'ipaanchoruuid': resolved_anchor, ++ }, ++ rules=ldap.MATCH_ALL ++ ) ++ ++ + class baseidoverride_add(LDAPCreate): + __doc__ = _('Add a new ID override.') + msg_summary = _('Added ID override "%(value)s"') +@@ -1128,6 +1162,15 @@ class idoverrideuser_find(baseidoverride_find): + msg_summary = ngettext('%(count)d User ID override matched', + '%(count)d User ID overrides matched', 0) + ++ def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, ++ **options): ++ result = super(idoverrideuser_find, self).pre_callback( ++ ldap, filter, attrs_list, base_dn, scope, *args, **options ++ ) ++ filter, base_dn, scope = result ++ filter = self.obj.filter_for_anchor(ldap, filter, options, 'user') ++ return filter, base_dn, scope ++ + def post_callback(self, ldap, entries, truncated, *args, **options): + truncated = super(idoverrideuser_find, self).post_callback( + ldap, entries, truncated, *args, **options) +@@ -1173,6 +1216,15 @@ class idoverridegroup_find(baseidoverride_find): + msg_summary = ngettext('%(count)d Group ID override matched', + '%(count)d Group ID overrides matched', 0) + ++ def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, ++ **options): ++ result = super(idoverridegroup_find, self).pre_callback( ++ ldap, filter, attrs_list, base_dn, scope, *args, **options ++ ) ++ filter, base_dn, scope = result ++ filter = self.obj.filter_for_anchor(ldap, filter, options, 'group') ++ return filter, base_dn, scope ++ + + @register() + class idoverridegroup_show(baseidoverride_show): + +From 11b06d24a94c5e92a0275df759bc81f0fc81d802 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Dec 07 2018 15:06:13 +0000 +Subject: Add integration tests for idviews + + +Add several tests to verify new anchor override and general idview +override functionality. + +Fixes: https://pagure.io/freeipa/issue/6594 +Signed-off-by: Christian Heimes +Reviewed-By: Rob Crittenden + +--- + +diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py +index 36178e8..3548f2b 100644 +--- a/ipatests/pytest_ipa/integration/tasks.py ++++ b/ipatests/pytest_ipa/integration/tasks.py +@@ -1576,9 +1576,19 @@ def strip_cert_header(pem): + return pem + + +-def user_add(host, login): +- host.run_command([ ++def user_add(host, login, first='test', last='user', extra_args=()): ++ cmd = [ + "ipa", "user-add", login, +- "--first", "test", +- "--last", "user" +- ]) ++ "--first", first, ++ "--last", last ++ ] ++ cmd.extend(extra_args) ++ return host.run_command(cmd) ++ ++ ++def group_add(host, groupname, extra_args=()): ++ cmd = [ ++ "ipa", "group-add", groupname, ++ ] ++ cmd.extend(extra_args) ++ return host.run_command(cmd) +diff --git a/ipatests/test_integration/test_idviews.py b/ipatests/test_integration/test_idviews.py +index 9a8f379..6ede4d0 100644 +--- a/ipatests/test_integration/test_idviews.py ++++ b/ipatests/test_integration/test_idviews.py +@@ -165,6 +165,7 @@ class TestRulesWithServicePrincipals(IntegrationTest): + + topology = 'star' + num_replicas = 0 ++ num_clients = 0 + service_certprofile = 'caIPAserviceCert' + caacl = 'test_caacl' + keytab = "replica.keytab" +@@ -238,3 +239,133 @@ EOF + raiseonerr=False) + assert(result.returncode == 0), ( + 'Failed to add a cert to custom certprofile') ++ ++ ++class TestIDViews(IntegrationTest): ++ topology = 'star' ++ num_replicas = 0 ++ num_clients = 1 ++ ++ user1 = 'testuser1' ++ user1_uid = 10001 ++ user1_gid = 10001 ++ user1_uid_override = 5001 ++ user1_gid_override = 6001 ++ ++ user2 = 'testuser2' ++ user2_uid = 10002 ++ user2_gid = 10002 ++ ++ group1 = 'testgroup1' ++ group1_gid = 11001 ++ group1_gid_override = 7001 ++ ++ idview = 'testview' ++ ++ @classmethod ++ def install(cls, mh): ++ super(TestIDViews, cls).install(mh) ++ master = cls.master ++ client = cls.clients[0] ++ tasks.kinit_admin(master) ++ ++ tasks.user_add( ++ master, cls.user1, first='Test1', ++ extra_args=[ ++ '--uid', str(cls.user1_uid), ++ '--gidnumber', str(cls.user1_gid), ++ ] ++ ) ++ tasks.user_add( ++ master, cls.user2, first='Test2', ++ extra_args=[ ++ '--uid', str(cls.user2_uid), ++ '--gidnumber', str(cls.user2_gid), ++ ] ++ ) ++ tasks.group_add( ++ master, cls.group1, extra_args=['--gid', str(cls.group1_gid)] ++ ) ++ ++ master.run_command(['ipa', 'idview-add', cls.idview]) ++ ++ # add overrides for user1 and its default user group ++ master.run_command([ ++ 'ipa', 'idoverrideuser-add', cls.idview, cls.user1, ++ '--uid', str(cls.user1_uid_override), ++ '--gid', str(cls.user1_gid_override), ++ '--homedir', '/special-home/{}'.format(cls.user1), ++ '--shell', '/bin/special' ++ ]) ++ master.run_command([ ++ 'ipa', 'idoverridegroup-add', cls.idview, cls.group1, ++ '--gid', str(cls.group1_gid_override), ++ ]) ++ ++ # ID view overrides don't work on IPA masters ++ master.run_command([ ++ 'ipa', 'idview-apply', cls.idview, ++ '--hosts', client.hostname ++ ]) ++ # finally restart SSSD to materialize idviews ++ client.run_command(['systemctl', 'restart', 'sssd.service']) ++ ++ def test_useroverride(self): ++ result = self.clients[0].run_command(['id', self.user1]) ++ assert 'uid={}'.format(self.user1_uid_override) in result.stdout_text ++ assert 'gid={}'.format(self.user1_gid_override) in result.stdout_text ++ ++ result = self.clients[0].run_command( ++ ['getent', 'passwd', str(self.user1_uid_override)] ++ ) ++ expected = '{}:*:{}:{}'.format( ++ self.user1, self.user1_uid_override, self.user1_gid_override ++ ) ++ assert expected in result.stdout_text ++ ++ result = self.master.run_command(['id', self.user1]) ++ assert 'uid={}'.format(self.user1_uid) in result.stdout_text ++ assert 'gid={}'.format(self.user1_gid) in result.stdout_text ++ ++ def test_useroverride_original_uid(self): ++ # It's still possible to request the user with its original UID. In ++ # this case the getent command returns the user with override uid. ++ result = self.clients[0].run_command( ++ ['getent', 'passwd', str(self.user1_uid)] ++ ) ++ expected = '{}:*:{}:{}'.format( ++ self.user1, self.user1_uid_override, self.user1_gid_override ++ ) ++ assert expected in result.stdout_text ++ ++ def test_anchor_username(self): ++ result = self.master.run_command([ ++ 'ipa', 'idoverrideuser-find', self.idview, '--anchor', self.user1 ++ ]) ++ expected = "Anchor to override: {}".format(self.user1) ++ assert expected in result.stdout_text ++ ++ def test_groupoverride(self): ++ result = self.clients[0].run_command(['getent', 'group', self.group1]) ++ assert ':{}:'.format(self.group1_gid_override) in result.stdout_text ++ ++ result = self.master.run_command(['getent', 'group', self.group1]) ++ assert ':{}:'.format(self.group1_gid) in result.stdout_text ++ ++ def test_groupoverride_system_objects(self): ++ # group override for user group should fail ++ result = self.master.run_command( ++ ['ipa', 'idoverridegroup-add', self.idview, self.user1, ++ '--gid', str(self.user1_gid_override)], ++ raiseonerr=False ++ ) ++ assert result.returncode == 1 ++ assert "cannot be overridden" in result.stderr_text ++ ++ def test_anchor_groupname(self): ++ result = self.master.run_command([ ++ 'ipa', 'idoverridegroup-find', self.idview, ++ '--anchor', self.group1 ++ ]) ++ expected = "Anchor to override: {}".format(self.group1) ++ assert expected in result.stdout_text + +ONLY APPLYING TO ipatests/prci_definitions/nightly_rawhide.yaml, other +files are not available or compatible + +From e86498ea2f8259118025e622cc5f1cf2c26f2757 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Dec 07 2018 15:06:13 +0000 +Subject: Run idviews integration tests in nightly + + +See: https://pagure.io/freeipa/issue/6594 +Signed-off-by: Christian Heimes +Reviewed-By: Rob Crittenden + +--- + +#diff --git a/ipatests/prci_definitions/nightly_f28.yaml b/ipatests/prci_definitions/nightly_f28.yaml +#index 8462c14..ac792f1 100644 +#--- a/ipatests/prci_definitions/nightly_f28.yaml +#+++ b/ipatests/prci_definitions/nightly_f28.yaml +#@@ -195,6 +195,18 @@ jobs: +# timeout: 10800 +# topology: *master_1repl +# +#+ fedora-28/test_idviews: +#+ requires: [fedora-28/build] +#+ priority: 50 +#+ job: +#+ class: RunPytest +#+ args: +#+ build_url: '{fedora-28/build_url}' +#+ test_suite: test_integration/test_idviews.py::TestIDViews +#+ template: *ci-master-f28 +#+ timeout: 3600 +#+ topology: *master_1repl_1client +#+ +# fedora-28/test_caless_TestServerInstall: +# requires: [fedora-28/build] +# priority: 50 +#diff --git a/ipatests/prci_definitions/nightly_master.yaml b/ipatests/prci_definitions/nightly_master.yaml +#index 3f2b346..953a60e 100644 +#--- a/ipatests/prci_definitions/nightly_master.yaml +#+++ b/ipatests/prci_definitions/nightly_master.yaml +#@@ -195,6 +195,18 @@ jobs: +# timeout: 10800 +# topology: *master_1repl +# +#+ fedora-28/test_idviews: +#+ requires: [fedora-29/build] +#+ priority: 50 +#+ job: +#+ class: RunPytest +#+ args: +#+ build_url: '{fedora-29/build_url}' +#+ test_suite: test_integration/test_idviews.py::TestIDViews +#+ template: *ci-master-f29 +#+ timeout: 3600 +#+ topology: *master_1repl_1client +#+ +# fedora-29/test_caless_TestServerInstall: +# requires: [fedora-29/build] +# priority: 50 +diff --git a/ipatests/prci_definitions/nightly_rawhide.yaml b/ipatests/prci_definitions/nightly_rawhide.yaml +index bdc34d2..e74e5f6 100644 +--- a/ipatests/prci_definitions/nightly_rawhide.yaml ++++ b/ipatests/prci_definitions/nightly_rawhide.yaml +@@ -195,6 +195,18 @@ jobs: + timeout: 10800 + topology: *master_1repl + ++ fedora-28/test_idviews: ++ requires: [fedora-rawhide/build] ++ priority: 50 ++ job: ++ class: RunPytest ++ args: ++ build_url: '{fedora-rawhide/build_url}' ++ test_suite: test_integration/test_idviews.py::TestIDViews ++ template: *ci-master-frawhide ++ timeout: 3600 ++ topology: *master_1repl_1client ++ + fedora-rawhide/test_caless_TestServerInstall: + requires: [fedora-rawhide/build] + priority: 50 + diff --git a/SOURCES/0030-Fix-systemd-user-HBAC-rule.patch b/SOURCES/0030-Fix-systemd-user-HBAC-rule.patch new file mode 100644 index 0000000..50fe287 --- /dev/null +++ b/SOURCES/0030-Fix-systemd-user-HBAC-rule.patch @@ -0,0 +1,58 @@ +From b3f06994b7b44a0f9cd0c6bd0302c9db87dc2502 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Tue, 15 Jan 2019 17:33:56 +0100 +Subject: [PATCH] Fix systemd-user HBAC rule + +2ef6e14c5a87724a3b37dd5f0817af48c4411e03 added an invalid HBAC rule that +encoded the service wrongly. + +See: https://bugzilla.redhat.com/show_bug.cgi?id=1643928 +Fixes: https://pagure.io/freeipa/issue/7831 +Signed-off-by: Christian Heimes +--- + install/share/default-hbac.ldif | 2 +- + ipatests/test_integration/test_commands.py | 12 +++++++++--- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/install/share/default-hbac.ldif b/install/share/default-hbac.ldif +index 8dd90685c..c89bd3eef 100644 +--- a/install/share/default-hbac.ldif ++++ b/install/share/default-hbac.ldif +@@ -21,7 +21,7 @@ cn: allow_systemd-user + accessruletype: allow + usercategory: all + hostcategory: all +-servicecategory: systemd-user ++memberService: cn=systemd-user,cn=hbacservices,cn=hbac,$SUFFIX + ipaenabledflag: TRUE + description: Allow pam_systemd to run user@.service to create a system user session + ipauniqueid: autogenerate +diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py +index 1fb6450a2..8b2c84fc6 100644 +--- a/ipatests/test_integration/test_commands.py ++++ b/ipatests/test_integration/test_commands.py +@@ -500,12 +500,18 @@ class TestIPACommand(IntegrationTest): + # https://pagure.io/freeipa/issue/7831 + tasks.kinit_admin(self.master) + # check for presence +- self.master.run_command( +- ['ipa', 'hbacrule-show', 'allow_systemd-user'] +- ) + self.master.run_command( + ['ipa', 'hbacsvc-show', 'systemd-user'] + ) ++ result = self.master.run_command( ++ ['ipa', 'hbacrule-show', 'allow_systemd-user', '--all'] ++ ) ++ lines = set(l.strip() for l in result.stdout_text.split('\n')) ++ assert 'User category: all' in lines ++ assert 'Host category: all' in lines ++ assert 'Enabled: TRUE' in lines ++ assert 'Services: systemd-user' in lines ++ assert 'accessruletype: allow' in lines + + # delete both + self.master.run_command( +-- +2.20.1 + diff --git a/SOURCES/0031-ipa-client-automount-handle-NFS-configuration-file-c.patch b/SOURCES/0031-ipa-client-automount-handle-NFS-configuration-file-c.patch new file mode 100644 index 0000000..04ddf59 --- /dev/null +++ b/SOURCES/0031-ipa-client-automount-handle-NFS-configuration-file-c.patch @@ -0,0 +1,189 @@ +From c69875c8afdd877baf7139c0cd5241f70105cbd4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= +Date: Tue, 26 Feb 2019 13:59:06 +0100 +Subject: [PATCH] ipa-client-automount: handle NFS configuration file changes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +nfs-utils in Fedora 30 and later switched its configuration +file from /etc/sysconfig/nfs to /etc/nfs.conf, providing a +conversion service (nfs-convert.service) for upgrades. +However, for new installs the original configuration file +is missing. This change: +* adds a tuple-based osinfo.version_number method to handle + more kinds of OS versioning schemes +* detects RHEL and Fedora versions with the the new nfs-utils + behavior +* avoids backing up the new NFS configuration file as we do + not have to modify it. + +See: https://bugzilla.redhat.com/show_bug.cgi?id=1676981 + +Fixes: https://pagure.io/freeipa/issue/7868 +Signed-off-by: François Cami +Reviewed-By: Alexander Bokovoy +Reviewed-By: Christian Heimes +Reviewed-By: Rob Crittenden +--- + client/ipa-client-automount.in | 18 ++++++++++-------- + ipaplatform/fedora/constants.py | 9 ++++++++- + ipaplatform/fedora/paths.py | 3 +++ + ipaplatform/fedora/services.py | 2 +- + ipaplatform/osinfo.py | 9 +++++++++ + ipaplatform/rhel/constants.py | 7 +++++++ + ipaplatform/rhel/paths.py | 4 +++- + 7 files changed, 41 insertions(+), 11 deletions(-) + +diff --git a/client/ipa-client-automount.in b/client/ipa-client-automount.in +index 15926bd..f9eda9c 100755 +--- a/client/ipa-client-automount.in ++++ b/client/ipa-client-automount.in +@@ -335,14 +335,16 @@ def configure_nfs(fstore, statestore): + """ + Configure secure NFS + """ +- replacevars = { +- constants.SECURE_NFS_VAR: 'yes', +- } +- ipautil.backup_config_and_replace_variables(fstore, +- paths.SYSCONFIG_NFS, replacevars=replacevars) +- tasks.restore_context(paths.SYSCONFIG_NFS) +- +- print("Configured %s" % paths.SYSCONFIG_NFS) ++ # Newer Fedora releases ship /etc/nfs.conf instead of /etc/sysconfig/nfs ++ # and do not require changes there. On these, SECURE_NFS_VAR == None ++ if constants.SECURE_NFS_VAR: ++ replacevars = { ++ constants.SECURE_NFS_VAR: 'yes', ++ } ++ ipautil.backup_config_and_replace_variables(fstore, ++ paths.SYSCONFIG_NFS, replacevars=replacevars) ++ tasks.restore_context(paths.SYSCONFIG_NFS) ++ print("Configured %s" % paths.SYSCONFIG_NFS) + + # Prepare the changes + # We need to use IPAChangeConf as simple regexp substitution +diff --git a/ipaplatform/fedora/constants.py b/ipaplatform/fedora/constants.py +index d48696e..744b30a 100644 +--- a/ipaplatform/fedora/constants.py ++++ b/ipaplatform/fedora/constants.py +@@ -10,6 +10,12 @@ This Fedora base platform module exports platform related constants. + from __future__ import absolute_import + + from ipaplatform.redhat.constants import RedHatConstantsNamespace ++from ipaplatform.osinfo import osinfo ++ ++# Fedora 28 and earlier use /etc/sysconfig/nfs ++# Fedora 30 and later use /etc/nfs.conf ++# Fedora 29 has both ++HAS_NFS_CONF = osinfo.version_number >= (30,) + + + class FedoraConstantsNamespace(RedHatConstantsNamespace): +@@ -22,6 +28,7 @@ class FedoraConstantsNamespace(RedHatConstantsNamespace): + # secure remote password, and DSA cert authentication. + # see https://fedoraproject.org/wiki/Changes/CryptoPolicy + TLS_HIGH_CIPHERS = "PROFILE=SYSTEM:!3DES:!PSK:!SRP:!aDSS" +- ++ if HAS_NFS_CONF: ++ SECURE_NFS_VAR = None + + constants = FedoraConstantsNamespace() +diff --git a/ipaplatform/fedora/paths.py b/ipaplatform/fedora/paths.py +index a9bdedf..4e993c0 100644 +--- a/ipaplatform/fedora/paths.py ++++ b/ipaplatform/fedora/paths.py +@@ -26,6 +26,7 @@ in Fedora-based systems. + from __future__ import absolute_import + + from ipaplatform.redhat.paths import RedHatPathNamespace ++from ipaplatform.fedora.constants import HAS_NFS_CONF + + + class FedoraPathNamespace(RedHatPathNamespace): +@@ -33,6 +34,8 @@ class FedoraPathNamespace(RedHatPathNamespace): + "/etc/httpd/conf.modules.d/02-ipa-wsgi.conf" + ) + NAMED_CRYPTO_POLICY_FILE = "/etc/crypto-policies/back-ends/bind.config" ++ if HAS_NFS_CONF: ++ SYSCONFIG_NFS = '/etc/nfs.conf' + + + paths = FedoraPathNamespace() +diff --git a/ipaplatform/fedora/services.py b/ipaplatform/fedora/services.py +index 5ff64f1..543cb1b 100644 +--- a/ipaplatform/fedora/services.py ++++ b/ipaplatform/fedora/services.py +@@ -34,7 +34,7 @@ fedora_system_units = redhat_services.redhat_system_units.copy() + # Fedora 28 and earlier have fedora-domainname.service. Starting from + # Fedora 29, the service is called nis-domainname.service as defined in + # ipaplatform.redhat.services. +-HAS_FEDORA_DOMAINNAME_SERVICE = int(osinfo.version_id) <= 28 ++HAS_FEDORA_DOMAINNAME_SERVICE = osinfo.version_number <= (28,) + + if HAS_FEDORA_DOMAINNAME_SERVICE: + fedora_system_units['domainname'] = 'fedora-domainname.service' +diff --git a/ipaplatform/osinfo.py b/ipaplatform/osinfo.py +index a38165d..35b024e 100644 +--- a/ipaplatform/osinfo.py ++++ b/ipaplatform/osinfo.py +@@ -178,6 +178,15 @@ class OSInfo(Mapping): + return self._info.get('VERSION_ID') + + @property ++ def version_number(self): ++ """Version number tuple based on version_id ++ """ ++ version_id = self._info.get('VERSION_ID') ++ if not version_id: ++ return () ++ return tuple(int(p) for p in version_id.split('.')) ++ ++ @property + def platform_ids(self): + """Ordered tuple of detected platforms (including override) + """ +diff --git a/ipaplatform/rhel/constants.py b/ipaplatform/rhel/constants.py +index 72335ac..073e332 100644 +--- a/ipaplatform/rhel/constants.py ++++ b/ipaplatform/rhel/constants.py +@@ -10,10 +10,17 @@ This RHEL base platform module exports platform related constants. + from __future__ import absolute_import + + from ipaplatform.redhat.constants import RedHatConstantsNamespace ++from ipaplatform.osinfo import osinfo ++ ++# RHEL 7 and earlier use /etc/sysconfig/nfs ++# RHEL 8 uses /etc/nfs.conf ++HAS_NFS_CONF = osinfo.version_number >= (8,) + + + class RHELConstantsNamespace(RedHatConstantsNamespace): + IPA_ADTRUST_PACKAGE_NAME = "ipa-server-trust-ad" + IPA_DNS_PACKAGE_NAME = "ipa-server-dns" ++ if HAS_NFS_CONF: ++ SECURE_NFS_VAR = None + + constants = RHELConstantsNamespace() +diff --git a/ipaplatform/rhel/paths.py b/ipaplatform/rhel/paths.py +index d8b64ab..c081ada 100644 +--- a/ipaplatform/rhel/paths.py ++++ b/ipaplatform/rhel/paths.py +@@ -26,10 +26,12 @@ in RHEL-based systems. + from __future__ import absolute_import + + from ipaplatform.redhat.paths import RedHatPathNamespace ++from ipaplatform.rhel.constants import HAS_NFS_CONF + + + class RHELPathNamespace(RedHatPathNamespace): +- pass ++ if HAS_NFS_CONF: ++ SYSCONFIG_NFS = '/etc/nfs.conf' + + + paths = RHELPathNamespace() +-- +2.9.3 + diff --git a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch new file mode 100644 index 0000000..dd6dc07 --- /dev/null +++ b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch @@ -0,0 +1,2748 @@ +From 63b3030e2e2f6411ad29448746b96bb9658467f8 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 02/72] client/man/default.conf.5: Change branding to IPA + and Identity Management + +--- + client/man/default.conf.5 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/client/man/default.conf.5 b/client/man/default.conf.5 +index f21d9d5b7..d6c1e42d1 100644 +--- a/client/man/default.conf.5 ++++ b/client/man/default.conf.5 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "default.conf" "5" "Feb 21 2011" "FreeIPA" "FreeIPA Manual Pages" ++.TH "default.conf" "5" "Feb 21 2011" "IPA" "IPA Manual Pages" + .SH "NAME" + default.conf \- IPA configuration file + .SH "SYNOPSIS" +-- +2.17.1 + + +From 3fe816976ea30d363ae5c6086b8daaaadaa5d7f7 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 03/72] client/man/ipa-certupdate.1: Change branding to IPA + and Identity Management + +--- + client/man/ipa-certupdate.1 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/client/man/ipa-certupdate.1 b/client/man/ipa-certupdate.1 +index d95790a36..431b395a9 100644 +--- a/client/man/ipa-certupdate.1 ++++ b/client/man/ipa-certupdate.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Jan Cholasta + .\" +-.TH "ipa-certupdate" "1" "Jul 2 2014" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-certupdate" "1" "Jul 2 2014" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-certupdate \- Update local IPA certificate databases with certificates from the server + .SH "SYNOPSIS" +-- +2.17.1 + + +From eca4cf0eabb4dee96ca01c02910153147e58ec4d Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 04/72] client/man/ipa-client-automount.1: Change branding + to IPA and Identity Management + +--- + client/man/ipa-client-automount.1 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/client/man/ipa-client-automount.1 b/client/man/ipa-client-automount.1 +index 343f64160..3f7c7d506 100644 +--- a/client/man/ipa-client-automount.1 ++++ b/client/man/ipa-client-automount.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "ipa-client-automount" "1" "May 25 2012" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-client-automount" "1" "May 25 2012" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-client\-automount \- Configure automount and NFS for IPA + .SH "SYNOPSIS" +-- +2.17.1 + + +From e4097608a167f41998e863dfed0e3d135c54b6a0 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 05/72] client/man/ipa-client-install.1: Change branding to + IPA and Identity Management + +--- + client/man/ipa-client-install.1 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/client/man/ipa-client-install.1 b/client/man/ipa-client-install.1 +index a20bec9a1..d7347ed37 100644 +--- a/client/man/ipa-client-install.1 ++++ b/client/man/ipa-client-install.1 +@@ -1,7 +1,7 @@ + .\" A man page for ipa-client-install + .\" Copyright (C) 2008-2016 FreeIPA Contributors see COPYING for license + .\" +-.TH "ipa-client-install" "1" "Dec 19 2016" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-client-install" "1" "Dec 19 2016" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-client\-install \- Configure an IPA client + .SH "SYNOPSIS" +-- +2.17.1 + + +From 3bfd21f6778e288b5094262aa481a835b49cc0f4 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 06/72] client/man/ipa-getkeytab.1: Change branding to IPA + and Identity Management + +--- + client/man/ipa-getkeytab.1 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/client/man/ipa-getkeytab.1 b/client/man/ipa-getkeytab.1 +index 20ceee2e6..061798693 100644 +--- a/client/man/ipa-getkeytab.1 ++++ b/client/man/ipa-getkeytab.1 +@@ -17,7 +17,7 @@ + .\" Author: Karl MacMillan + .\" Author: Simo Sorce + .\" +-.TH "ipa-getkeytab" "1" "Oct 10 2007" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-getkeytab" "1" "Oct 10 2007" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-getkeytab \- Get a keytab for a Kerberos principal + .SH "SYNOPSIS" +@@ -117,7 +117,7 @@ GSSAPI or EXTERNAL. + \fB\-r\fR + Retrieve mode. Retrieve an existing key from the server instead of generating a + new one. This is incompatible with the \-\-password option, and will work only +-against a FreeIPA server more recent than version 3.3. The user requesting the ++against a IPA server more recent than version 3.3. The user requesting the + keytab must have access to the keys for this operation to succeed. + .SH "EXAMPLES" + Add and retrieve a keytab for the NFS service principal on +-- +2.17.1 + + +From 812ccffd549367cac3e4d2896b231b7b278e0b92 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 07/72] client/man/ipa-join.1: Change branding to IPA and + Identity Management + +--- + client/man/ipa-join.1 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/client/man/ipa-join.1 b/client/man/ipa-join.1 +index d88160784..30b667558 100644 +--- a/client/man/ipa-join.1 ++++ b/client/man/ipa-join.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "ipa-join" "1" "Oct 8 2009" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-join" "1" "Oct 8 2009" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-join \- Join a machine to an IPA realm and get a keytab for the host service principal + .SH "SYNOPSIS" +-- +2.17.1 + + +From 3cac7f131059c01306b1db34fc30345add3fcf11 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 08/72] client/man/ipa-rmkeytab.1: Change branding to IPA + and Identity Management + +--- + client/man/ipa-rmkeytab.1 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/client/man/ipa-rmkeytab.1 b/client/man/ipa-rmkeytab.1 +index 53f775439..2c8218c94 100644 +--- a/client/man/ipa-rmkeytab.1 ++++ b/client/man/ipa-rmkeytab.1 +@@ -17,7 +17,7 @@ + .\" Author: Rob Crittenden + .\" + .\" +-.TH "ipa-rmkeytab" "1" "Oct 30 2009" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-rmkeytab" "1" "Oct 30 2009" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-rmkeytab \- Remove a kerberos principal from a keytab + .SH "SYNOPSIS" +-- +2.17.1 + + +From 0373bb1499f50bf4c04becabf2e773dd5977060e Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 09/72] client/man/ipa.1: Change branding to IPA and + Identity Management + +--- + client/man/ipa.1 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/client/man/ipa.1 b/client/man/ipa.1 +index f9fae7c0d..2fb21b52d 100644 +--- a/client/man/ipa.1 ++++ b/client/man/ipa.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Pavel Zuna + .\" +-.TH "ipa" "1" "Apr 29 2016" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa" "1" "Apr 29 2016" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa \- IPA command\-line interface + .SH "SYNOPSIS" +-- +2.17.1 + + +From 36b7dce706ec2b0b650c51cea24be0655fd0c096 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 7 Oct 2018 12:25:39 +0300 +Subject: [PATCH 10/72] install/html/ssbrowser.html: Change branding to IPA + and Identity Management + +--- + install/html/ssbrowser.html | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/install/html/ssbrowser.html b/install/html/ssbrowser.html +index faa7e657b..89ada7cb1 100644 +--- a/install/html/ssbrowser.html ++++ b/install/html/ssbrowser.html +@@ -2,7 +2,7 @@ + + + +- IPA: Identity Policy Audit ++ Identity Management + + +