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 <flo@redhat.com>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
Florence Blanc-Renaud 2021-10-08 15:47:06 +02:00
parent b054532658
commit ed001c97ee
11 changed files with 196 additions and 5 deletions

View File

@ -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')

View File

@ -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)
########################################################

View File

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

View File

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

View File

@ -17,6 +17,12 @@
prepend_user_name="no"
argument_passing_method="cmdline"/>
</method>
<method name="config_enable_sid">
<helper exec="@ODDJOBDIR@/org.freeipa.server.config-enable-sid"
arguments="10"
prepend_user_name="no"
argument_passing_method="cmdline"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<allow min_uid="0" max_uid="0"/>

View File

@ -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()

View File

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

View File

@ -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.")

View File

@ -17,12 +17,16 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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(

View File

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

View File

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