Skip to content

Commit

Permalink
Add initial round of changes for SSSD support
Browse files Browse the repository at this point in the history
This commit provides equivalent functionality from SSSD that
we were getting from nss-pam-ldapd (nslcd)

* remove nslcd from build and runtime requirements
* add truenas-sssd to build and runtime requirements
* slightly refactor LDAP plugin to restart new sssd service
  rather than nslcd service.
* remove mako file for nslcd and create one for sssd
* remove murmurhash3 python implementation and use one provided
  by sssd.

TODO:
- add user and group UI caching for LDAP users
- improve SSSD status checks
- add migration to comment-out auxiliary parameters for LDAP plugin
  • Loading branch information
anodos325 committed Apr 26, 2024
1 parent 6bc1d37 commit bf99b91
Show file tree
Hide file tree
Showing 13 changed files with 137 additions and 286 deletions.
2 changes: 1 addition & 1 deletion debian/debian/control
Expand Up @@ -26,7 +26,6 @@ Depends: acl,
middlewared,
nfs-common,
nfs-kernel-server,
nslcd,
net-tools,
netdata-core,
netdata-plugins-bash,
Expand All @@ -40,6 +39,7 @@ Depends: acl,
proftpd-mod-crypto,
python3-midcli,
truenas-samba,
truenas-sssd,
snmpd,
sudo,
systemd-coredump,
Expand Down
4 changes: 2 additions & 2 deletions src/middlewared/debian/control
Expand Up @@ -5,7 +5,6 @@ Maintainer: William Grzybowski <william@grzy.org>
Build-Depends: alembic,
debhelper-compat (= 12),
dh-python,
nslcd,
python3-acme,
python3-aiohttp,
python3-aiorwlock,
Expand Down Expand Up @@ -69,6 +68,7 @@ Build-Depends: alembic,
python3-zettarepl,
sqlite3,
truenas-samba,
truenas-sssd,
truenas-files
Standards-Version: 4.4.0
Homepage: https://github.com/freenas/freenas
Expand Down Expand Up @@ -96,7 +96,6 @@ Depends: alembic,
lm-sensors,
lsof,
mdadm,
nslcd,
chrony,
nvidia-container-runtime,
openresolv,
Expand Down Expand Up @@ -162,6 +161,7 @@ Depends: alembic,
restic,
rsync,
truenas-samba,
truenas-sssd,
scst,
scstadmin,
sedutil,
Expand Down
82 changes: 0 additions & 82 deletions src/middlewared/middlewared/etc_files/local/nslcd.conf.mako

This file was deleted.

86 changes: 86 additions & 0 deletions src/middlewared/middlewared/etc_files/sssd/sssd.conf.mako
@@ -0,0 +1,86 @@
#
# NSLCD.CONF(5) The configuration file for LDAP nameservice daemon
#
<%
from middlewared.plugins.ldap_ import constants
from middlewared.plugins.ldap_ import utils
ldap = middleware.call_sync('ldap.config')
kerberos_realm = None
aux = []
map_params = utils.attribute_maps_data_to_params(ldap[constants.LDAP_ATTRIBUTE_MAP_SCHEMA_NAME])
search_params = utils.search_base_data_to_params(ldap[constants.LDAP_SEARCH_BASES_SCHEMA_NAME])
min_uid = 1000
kerberos_realm = None
certpath = None
if ldap['certificate']:
try:
cert = middleware.call_sync('certificate.query', [('id', '=', ldap['certificate'])], {'get': True})
except IndexError:
pass
else:
certpath = cert['certificate_path']
keypath = cert['privatekey_path']
if ldap['kerberos_realm']:
kerberos_realm = middleware.call_sync(
'kerberos.realm.query',
[('id', '=', ldap['kerberos_realm'])],
{'get': True}
)['realm']
ldap_enabled = ldap['enable']
if ldap_enabled:
domain = kerberos_realm or ldap['hostname'][0]
ldap_enabled = ldap['enable']
for param in ldap['auxiliary_parameters'].splitlines():
param = param.strip()
if not param.startswith('nss_min_uid'):
aux.append(param)
else:
try:
min_uid = param.split()[1]
except Exception:
pass
%>
% if ldap_enabled:
[sssd]
domains = ${domain}
services = nss, pam
config_file_version = 2

[domain/${domain}]
id_provider = ldap
auth_provider = ldap
ldap_uri = ${','.join(ldap['uri_list'])}
ldap_search_base = ${ldap['basedn']}
% if ldap['ssl'] == 'START_TLS':
ldap_id_use_start_tls = true
% endif
ldap_tls_cacert = /etc/ssl/certs/ca-certificates.crt
% if certpath:
ldap_tls_cert = ${certpath}
ldap_tls_key = ${keypath}
% endif
ldap_tls_reqcert = ${'demand' if ldap['validate_certificates'] else 'allow'}
% if ldap['binddn'] and ldap['bindpw']:
ldap_default_bind_dn = ${ldap['binddn']}
ldap_default_authtok = ${ldap['bindpw']}
% endif
enumerate = ${not ldap['disable_freenas_cache']}
% if kerberos_realm:
ldap_sasl_mech = GSSAPI
ldap_sasl_realm = ${kerberos_realm}
% if ldap['kerberos_principal']:
ldap_sasl_authid = ldap['kerberos_principal']
% endif
% endif
timeout = ${ldap['timeout']}
ldap_schema = ${ldap['schema'].lower()}
${'\n '.join(search_params)}
${'\n '.join(map_params)}
% if aux:
${'\n '.join(aux)}
% endif
% endif
2 changes: 1 addition & 1 deletion src/middlewared/middlewared/plugins/etc.py
Expand Up @@ -122,7 +122,7 @@ class EtcService(Service):
],
'ldap': [
{'type': 'mako', 'path': 'local/openldap/ldap.conf'},
{'type': 'mako', 'path': 'local/nslcd.conf', 'owner': 'nslcd', 'group': 'nslcd', 'mode': 0o0400},
{'type': 'mako', 'path': 'sssd/sssd.conf', 'mode': 0o0600},
],
'dhclient': [
{'type': 'mako', 'path': 'dhcp/dhclient.conf', 'local_path': 'dhclient.conf'},
Expand Down
47 changes: 6 additions & 41 deletions src/middlewared/middlewared/plugins/idmap.py
Expand Up @@ -15,6 +15,10 @@
from middlewared.utils import run, filter_list
from middlewared.validators import Range
from middlewared.plugins.smb import SMBPath
try:
from pysss_murmur import murmurhash3
except ImportError:
murmurhash3 = None


"""
Expand Down Expand Up @@ -366,47 +370,8 @@ async def get_sssd_low_range(self, domain, sssd_config=None, seed=0xdeadbeef):
range_max = sssd_config.get('range_max', 2000200000)
max_slices = int((range_max - range_low) / range_size)

data = bytearray(sid.encode())
datalen = len(data)
hash_ = seed
data_bytes = data

c1 = 0xcc9e2d51
c2 = 0x1b873593
r1 = 15
r2 = 13
n = 0xe6546b64

while datalen >= 4:
k = int.from_bytes(data_bytes[:4], byteorder='little') & 0xFFFFFFFF
data_bytes = data_bytes[4:]
datalen = datalen - 4
k = (k * c1) & 0xFFFFFFFF
k = (k << r1 | k >> 32 - r1) & 0xFFFFFFFF
k = (k * c2) & 0xFFFFFFFF
hash_ ^= k
hash_ = (hash_ << r2 | hash_ >> 32 - r2) & 0xFFFFFFFF
hash_ = (hash_ * 5 + n) & 0xFFFFFFFF

if datalen > 0:
k = 0
if datalen >= 3:
k = k | data_bytes[2] << 16
if datalen >= 2:
k = k | data_bytes[1] << 8
if datalen >= 1:
k = k | data_bytes[0]
k = (k * c1) & 0xFFFFFFFF
k = (k << r1 | k >> 32 - r1) & 0xFFFFFFFF
k = (k * c2) & 0xFFFFFFFF
hash_ ^= k

hash_ = (hash_ ^ len(data)) & 0xFFFFFFFF
hash_ ^= hash_ >> 16
hash_ = (hash_ * 0x85ebca6b) & 0xFFFFFFFF
hash_ ^= hash_ >> 13
hash_ = (hash_ * 0xc2b2ae35) & 0xFFFFFFFF
hash_ ^= hash_ >> 16
data = sid.encode()
hash_ = murmurhash3(data, len(data), seed)

return (hash_ % max_slices) * range_size + range_size

Expand Down
20 changes: 8 additions & 12 deletions src/middlewared/middlewared/plugins/ldap.py
Expand Up @@ -13,7 +13,6 @@
from middlewared.plugins.directoryservices import DSStatus, SSL
from middlewared.plugins.idmap import DSType
from middlewared.plugins.ldap_.ldap_client import LdapClient
from middlewared.plugins.ldap_.nslcd_utils import MidNslcdClient
from middlewared.plugins.ldap_ import constants
from middlewared.validators import Range

Expand Down Expand Up @@ -922,12 +921,9 @@ async def started(self):
except Exception as e:
raise CallError(e)

if not await self.middleware.call('service.started', 'nslcd'):
if not await self.middleware.call('service.started', 'sssd'):
await self.middleware.call('etc.generate', 'ldap')
await self.middleware.call('service.start', 'nslcd')

if not MidNslcdClient().is_alive():
raise CallError('nss-pam-ldapd daemon control socket is not available')
await self.middleware.call('service.start', 'sssd')

await self.set_state(DSStatus['HEALTHY'])
return True
Expand Down Expand Up @@ -988,8 +984,8 @@ async def __start(self, job):
await self.middleware.call('etc.generate', 'ldap')
await self.middleware.call('etc.generate', 'pam')

job.set_progress(30, 'Starting nslcd service')
await self.middleware.call('service.restart', 'nslcd')
job.set_progress(30, 'Starting sssd service')
await self.middleware.call('service.restart', 'sssd')

job.set_progress(50, 'Reconfiguring SMB service')
await self.middleware.call('smb.initialize_globals')
Expand Down Expand Up @@ -1042,8 +1038,8 @@ async def __stop(self, job):
job.set_progress(50, 'Clearing directory service cache.')
await self.middleware.call('service.stop', 'dscache')

job.set_progress(80, 'Stopping nslcd service.')
await self.middleware.call('service.stop', 'nslcd')
job.set_progress(80, 'Stopping sssd service.')
await self.middleware.call('service.stop', 'sssd')
await self.set_state(DSStatus['DISABLED'])
job.set_progress(100, 'LDAP directory service stopped.')

Expand All @@ -1058,8 +1054,8 @@ def fill_cache(self, job, force=False):
self.logger.debug('LDAP cache is disabled. Bypassing cache fill.')
return

pwd_list = MidNslcdClient().getpwall()
grp_list = MidNslcdClient().getgrall()
pwd_list = []
grp_list = []

for u in pwd_list:
entry = {
Expand Down
5 changes: 0 additions & 5 deletions src/middlewared/middlewared/plugins/ldap_/__init__.py
@@ -1,5 +0,0 @@
import sys
# nss-pam-ldapd generates constants at compile time that are stored in python
# nslcd client files in /usr/share/nslcd-utils. Hence, path is expanded to include
# this for the middleware nslcd client
sys.path.append('/usr/share/nslcd-utils')

0 comments on commit bf99b91

Please sign in to comment.