diff --git a/API.txt b/API.txt
index 6c80028bf..35d95a709 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 c43a7b427..fc206c965 100644
--- a/VERSION.m4
+++ b/VERSION.m4
@@ -86,8 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000)
# #
########################################################
define(IPA_API_VERSION_MAJOR, 2)
-# Last change: add subordinate id feature
-define(IPA_API_VERSION_MINOR, 243)
+# 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)