From ed001c97eec092d814ff9ecc57fafffe2d03657e Mon Sep 17 00:00:00 2001 From: Florence Blanc-Renaud Date: Fri, 8 Oct 2021 15:47:06 +0200 Subject: [PATCH] ipa config: add --enable-sid option Add new options to ipa config-mod, allowing to enable SID generation on upgraded servers: ipa config-mod --enable-sid --add-sids --netbios-name NAME The new option uses Dbus to launch an oddjob command, org.freeipa.server.config-enable-sid that runs the installation steps related to SID generation. --add-sids is optional and triggers the sid generation task that populates SID for existing users / groups. --netbios-name is optional and allows to specify the NetBIOS Name. When not provided, the NetBIOS name is generated based on the leading component of the DNS domain name. This command can be run multiple times. Fixes: https://pagure.io/freeipa/issue/8995 Signed-off-by: Florence Blanc-Renaud Reviewed-By: Christian Heimes Reviewed-By: Rob Crittenden Reviewed-By: Alexander Bokovoy --- API.txt | 5 +- VERSION.m4 | 4 +- freeipa.spec.in | 1 + install/oddjob/Makefile.am | 2 + .../etc/oddjobd.conf.d/ipa-server.conf.in | 6 ++ .../org.freeipa.server.config-enable-sid.in | 76 ++++++++++++++ ipaplatform/base/paths.py | 1 + ipaserver/install/adtrustinstance.py | 2 + ipaserver/plugins/config.py | 99 ++++++++++++++++++- ipaserver/rpcserver.py | 2 + selinux/ipa.te | 3 + 11 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 install/oddjob/org.freeipa.server.config-enable-sid.in diff --git a/API.txt b/API.txt index e4aeece15..b43e4a507 100644 --- a/API.txt +++ b/API.txt @@ -1076,11 +1076,13 @@ args: 0,1,1 option: Str('version?') output: Output('result') command: config_mod/1 -args: 0,29,3 +args: 0,32,3 +option: Flag('add_sids?', autofill=True, default=False) option: Str('addattr*', cli_name='addattr') option: Flag('all', autofill=True, cli_name='all', default=False) option: Str('ca_renewal_master_server?', autofill=False) option: Str('delattr*', cli_name='delattr') +option: Flag('enable_sid?', autofill=True, default=False) option: StrEnum('ipaconfigstring*', autofill=False, cli_name='ipaconfigstring', values=[u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout', u'KDC:Disable Default Preauth for SPNs']) option: Str('ipadefaultemaildomain?', autofill=False, cli_name='emaildomain') option: Str('ipadefaultloginshell?', autofill=False, cli_name='defaultshell') @@ -1102,6 +1104,7 @@ option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', v option: Bool('ipauserdefaultsubordinateid?', autofill=False, cli_name='user_default_subid') option: Str('ipauserobjectclasses*', autofill=False, cli_name='userobjectclasses') option: IA5Str('ipausersearchfields?', autofill=False, cli_name='usersearch') +option: Str('netbios_name?', autofill=False) option: Flag('raw', autofill=True, cli_name='raw', default=False) option: Flag('rights', autofill=True, default=False) option: Str('setattr*', cli_name='setattr') diff --git a/VERSION.m4 b/VERSION.m4 index 2a479ce44..182345861 100644 --- a/VERSION.m4 +++ b/VERSION.m4 @@ -86,8 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000) # # ######################################################## define(IPA_API_VERSION_MAJOR, 2) -# Last change: make sudorule option multivalue -define(IPA_API_VERSION_MINOR, 244) +# Last change: add enable_sid to config +define(IPA_API_VERSION_MINOR, 245) ######################################################## diff --git a/freeipa.spec.in b/freeipa.spec.in index 07ce6b292..952c1ad18 100755 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -1378,6 +1378,7 @@ fi %dir %{_libexecdir}/ipa/oddjob %attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.conncheck %attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.trust-enable-agent +%attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.config-enable-sid %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freeipa.server.conf %config(noreplace) %{_sysconfdir}/oddjobd.conf.d/ipa-server.conf %dir %{_libexecdir}/ipa/certmonger diff --git a/install/oddjob/Makefile.am b/install/oddjob/Makefile.am index 7aeb406a2..bd968eaba 100644 --- a/install/oddjob/Makefile.am +++ b/install/oddjob/Makefile.am @@ -7,6 +7,7 @@ dbusconfdir = $(sysconfdir)/dbus-1/system.d dist_noinst_DATA = \ com.redhat.idm.trust-fetch-domains.in \ org.freeipa.server.trust-enable-agent.in \ + org.freeipa.server.config-enable-sid.in \ etc/oddjobd.conf.d/oddjobd-ipa-trust.conf.in \ etc/oddjobd.conf.d/ipa-server.conf.in \ $(NULL) @@ -18,6 +19,7 @@ dist_oddjob_SCRIPTS = \ nodist_oddjob_SCRIPTS = \ com.redhat.idm.trust-fetch-domains \ org.freeipa.server.trust-enable-agent \ + org.freeipa.server.config-enable-sid \ $(NULL) diff --git a/install/oddjob/etc/oddjobd.conf.d/ipa-server.conf.in b/install/oddjob/etc/oddjobd.conf.d/ipa-server.conf.in index 640b510aa..a79640f88 100644 --- a/install/oddjob/etc/oddjobd.conf.d/ipa-server.conf.in +++ b/install/oddjob/etc/oddjobd.conf.d/ipa-server.conf.in @@ -17,6 +17,12 @@ prepend_user_name="no" argument_passing_method="cmdline"/> + + + diff --git a/install/oddjob/org.freeipa.server.config-enable-sid.in b/install/oddjob/org.freeipa.server.config-enable-sid.in new file mode 100644 index 000000000..ff5fb49e2 --- /dev/null +++ b/install/oddjob/org.freeipa.server.config-enable-sid.in @@ -0,0 +1,76 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2021 FreeIPA Contributors see COPYING for license +# + +import logging + +from ipalib import api +from ipalib.install import sysrestore +from ipaplatform.paths import paths +from ipapython import ipaldap +from ipapython.admintool import AdminTool +from ipaserver.install import adtrust, adtrustinstance + +logger = logging.getLogger(__name__) + +class IPAConfigEnableSid(AdminTool): + command_name = "ipa-enable-sid" + log_file_name = paths.IPASERVER_ENABLESID_LOG + usage = "%prog" + description = "Enable SID generation" + + @classmethod + def add_options(cls, parser): + super(IPAConfigEnableSid, cls).add_options(parser) + + parser.add_option( + "--add-sids", + dest="add_sids", default=False, action="store_true", + help="Add SIDs for existing users and groups as the final step" + ) + + parser.add_option( + "--netbios-name", + dest="netbios_name", default=None, + help="NetBIOS name of the IPA domain" + ) + + parser.add_option( + "--reset-netbios-name", + dest="reset_netbios_name", default=False, action="store_true", + help="Force reset of the existing NetBIOS name" + ) + + + def validate_options(self): + super(IPAConfigEnableSid, self).validate_options(needs_root=True) + + def run(self): + api.bootstrap(in_server=True, confdir=paths.ETC_IPA) + api.finalize() + + try: + api.Backend.ldap2.connect() + fstore = sysrestore.FileStore(paths.SYSRESTORE) + + smb = adtrustinstance.ADTRUSTInstance(fstore, False) + smb.realm = api.env.realm + smb.autobind = ipaldap.AUTOBIND_ENABLED + smb.setup(api.env.host, api.env.realm, + self.options.netbios_name, + self.options.reset_netbios_name, + adtrust.DEFAULT_PRIMARY_RID_BASE, + adtrust.DEFAULT_SECONDARY_RID_BASE, + self.options.add_sids, + enable_compat=False) + smb.find_local_id_range() + smb.create_instance() + + finally: + if api.Backend.ldap2.isconnected(): + api.Backend.ldap2.disconnect() + + return 0 + +IPAConfigEnableSid.run_cli() diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index de217d9ef..42a47f1df 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -364,6 +364,7 @@ class BasePathNamespace: IPAREPLICA_CONNCHECK_LOG = "/var/log/ipareplica-conncheck.log" IPAREPLICA_INSTALL_LOG = "/var/log/ipareplica-install.log" IPARESTORE_LOG = "/var/log/iparestore.log" + IPASERVER_ENABLESID_LOG = "/var/log/ipaserver-enable-sid.log" IPASERVER_INSTALL_LOG = "/var/log/ipaserver-install.log" IPASERVER_ADTRUST_INSTALL_LOG = "/var/log/ipaserver-adtrust-install.log" IPASERVER_DNS_INSTALL_LOG = "/var/log/ipaserver-dns-install.log" diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py index a53760340..b7cd8f7d8 100644 --- a/ipaserver/install/adtrustinstance.py +++ b/ipaserver/install/adtrustinstance.py @@ -335,6 +335,8 @@ class ADTRUSTInstance(service.Service): # _ldap_mod does not return useful error codes, so we must check again # if the fallback group was created properly. try: + # Remove entry from cache otherwise get_entry won't find it + api.Backend.ldap2.remove_cache_entry(fb_group_dn) api.Backend.ldap2.get_entry(fb_group_dn) except errors.NotFound: self.print_msg("Failed to add fallback group.") diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py index ad3dd6a7f..eae401fc3 100644 --- a/ipaserver/plugins/config.py +++ b/ipaserver/plugins/config.py @@ -17,12 +17,16 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import dbus +import dbus.mainloop.glib +import logging from ipalib import api -from ipalib import Bool, Int, Str, IA5Str, StrEnum, DNParam +from ipalib import Bool, Int, Str, IA5Str, StrEnum, DNParam, Flag from ipalib import errors from ipalib.constants import MAXHOSTNAMELEN from ipalib.plugable import Registry +from ipalib.request import context from ipalib.util import validate_domain_name from .baseldap import ( LDAPObject, @@ -30,7 +34,12 @@ from .baseldap import ( LDAPRetrieve) from .selinuxusermap import validate_selinuxuser from ipalib import _ +from ipapython.admintool import ScriptError from ipapython.dn import DN +from ipaserver.plugins.privilege import principal_has_privilege +from ipaserver.install.adtrust import set_and_check_netbios_name + +logger = logging.getLogger(__name__) # 389-ds attributes that should be skipped in attribute checks OPERATIONAL_ATTRIBUTES = ('nsaccountlock', 'member', 'memberof', @@ -340,6 +349,24 @@ class config(LDAPObject): doc=_('DNSec key master'), flags={'virtual_attribute', 'no_create', 'no_update'} ), + Flag( + 'enable_sid?', + label=_('Setup SID configuration'), + doc=_('New users and groups automatically get a SID assigned'), + flags={'virtual_attribute', 'no_create'} + ), + Flag( + 'add_sids?', + label=_('Add SIDs'), + doc=_('Add SIDs for existing users and groups'), + flags={'virtual_attribute', 'no_create'} + ), + Str( + 'netbios_name?', + label=_('NetBIOS name of the IPA domain'), + doc=_('NetBIOS name of the IPA domain'), + flags={'virtual_attribute', 'no_create'} + ), ) def get_dn(self, *keys, **kwargs): @@ -479,6 +506,60 @@ class config(LDAPObject): class config_mod(LDAPUpdate): __doc__ = _('Modify configuration options.') + def _enable_sid(self, ldap, options): + # the user must have the Replication Administrators privilege + privilege = 'Replication Administrators' + if not principal_has_privilege(self.api, context.principal, privilege): + raise errors.ACIError( + info=_("not allowed to enable SID generation")) + + # NetBIOS name is either taken from options or generated + try: + netbios_name, reset_netbios_name = set_and_check_netbios_name( + options.get('netbios_name', None), True, self.api) + except ScriptError: + raise errors.ValidationError(name="NetBIOS name", + error=_('Up to 15 characters and only uppercase ASCII letters' + ', digits and dashes are allowed. Empty string is ' + 'not allowed.')) + + _ret = 0 + _stdout = '' + _stderr = '' + + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + method_options = [] + if options.get('add_sids', False): + method_options.extend(["--add-sids"]) + method_options.extend(["--netbios-name", netbios_name]) + if reset_netbios_name: + method_options.append("--reset-netbios-name") + # Dbus definition expects up to 10 arguments + method_options.extend([''] * (10 - len(method_options))) + + try: + bus = dbus.SystemBus() + obj = bus.get_object('org.freeipa.server', '/', + follow_name_owner_changes=True) + server = dbus.Interface(obj, 'org.freeipa.server') + _ret, _stdout, _stderr = server.config_enable_sid(*method_options) + except dbus.DBusException as e: + logger.error('Failed to call org.freeipa.server.config_enable_sid.' + 'DBus exception is %s', str(e)) + raise errors.ExecutionError(message=_('Failed to call DBus')) + + # The oddjob restarts dirsrv, we need to re-establish the conn + if self.api.Backend.ldap2.isconnected(): + self.api.Backend.ldap2.disconnect() + self.api.Backend.ldap2.connect(ccache=context.ccache_name) + + if _ret != 0: + logger.error("Helper config_enable_sid return code is %d", _ret) + raise errors.ExecutionError( + message=_('Configuration of SID failed. ' + 'See details in the error log')) + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if 'ipadefaultprimarygroup' in entry_attrs: @@ -606,13 +687,27 @@ class config_mod(LDAPUpdate): self.obj.validate_domain_resolution_order(entry_attrs) + # The options add_sids or netbios_name need the enable_sid option + for sid_option in ['add_sids', 'netbios_name']: + if options.get(sid_option, None) and not options['enable_sid']: + opt = "--" + sid_option.replace("_", "-") + error_message = _("You cannot specify %s without " + "the --enable-sid option" % opt) + raise errors.ValidationError( + name=opt, + error=error_message) + + if options['enable_sid']: + self._enable_sid(ldap, options) + return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): if (isinstance(exc, errors.EmptyModlist) and call_func.__name__ == 'update_entry' and - 'ca_renewal_master_server' in options): + ('ca_renewal_master_server' in options or + 'enable_sid' in options)): return super(config_mod, self).exc_callback( diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py index e612528e0..20c536e4d 100644 --- a/ipaserver/rpcserver.py +++ b/ipaserver/rpcserver.py @@ -383,6 +383,8 @@ class WSGIExecutioner(Executioner): if self.api.env.debug: time_start = time.perf_counter_ns() try: + if 'KRB5CCNAME' in environ: + setattr(context, "ccache_name", environ['KRB5CCNAME']) if ('HTTP_ACCEPT_LANGUAGE' in environ): lang_reg_w_q = environ['HTTP_ACCEPT_LANGUAGE'].split(',')[0] lang_reg = lang_reg_w_q.split(';')[0] diff --git a/selinux/ipa.te b/selinux/ipa.te index 7492fca04..d18a4010d 100644 --- a/selinux/ipa.te +++ b/selinux/ipa.te @@ -155,6 +155,9 @@ manage_dirs_pattern(ipa_helper_t, ipa_var_run_t, ipa_var_run_t) manage_files_pattern(ipa_helper_t, ipa_var_run_t, ipa_var_run_t) files_pid_filetrans(ipa_helper_t, ipa_var_run_t, { dir file }) +manage_files_pattern(ipa_helper_t, ipa_tmp_t, ipa_tmp_t) +files_tmp_filetrans(ipa_helper_t, ipa_tmp_t, { file }) + kernel_read_system_state(ipa_helper_t) kernel_read_network_state(ipa_helper_t)