diff --git a/nss_cache/sources/ldapsource.py b/nss_cache/sources/ldapsource.py index b9f5a654..b03fe7c2 100644 --- a/nss_cache/sources/ldapsource.py +++ b/nss_cache/sources/ldapsource.py @@ -655,7 +655,9 @@ def Transform(self, obj): if hasattr(self, 'uidregex'): pw.name = ''.join([x for x in self.uidregex.findall(pw.name)]) - if 'loginShell' in obj: + if 'override_shell' in self.conf: + pw.shell = self.conf['override_shell'] + elif 'loginShell' in obj: pw.shell = obj['loginShell'][0] else: pw.shell = '' diff --git a/nss_cache/sources/ldapsource_test.py b/nss_cache/sources/ldapsource_test.py index 517b8af0..7fe8ff21 100644 --- a/nss_cache/sources/ldapsource_test.py +++ b/nss_cache/sources/ldapsource_test.py @@ -302,6 +302,59 @@ def testGetPasswdMap(self): self.assertEqual('Testguy McTest', first.name) + def testGetPasswdMapWithShellOverride(self): + test_posix_account = ('cn=test,ou=People,dc=example,dc=com', + {'uidNumber': [1000], + 'gidNumber': [1000], + 'uid': ['Testguy McTest'], + 'cn': ['test'], + 'homeDirectory': ['/home/test'], + 'loginShell': ['/bin/sh'], + 'userPassword': ['p4ssw0rd'], + 'modifyTimestamp': ['20070227012807Z']}) + config = dict(self.config) + config['override_shell'] = '/bin/false' + attrlist = ['uid', 'uidNumber', 'gidNumber', + 'gecos', 'cn', 'homeDirectory', + 'fullName', + 'loginShell', 'modifyTimestamp'] + + mock_rlo = self.mox.CreateMock(ldap.ldapobject.ReconnectLDAPObject) + mock_rlo.simple_bind_s( + cred='TEST_BIND_PASSWORD', + who='TEST_BIND_DN') + mock_rlo.search_ext(base='TEST_BASE', + filterstr='TEST_FILTER', + scope=ldap.SCOPE_ONELEVEL, + attrlist=mox.SameElementsAs(attrlist), + serverctrls=mox.Func(self.compareSPRC())).AndReturn('TEST_RES') + + mock_rlo.result3('TEST_RES', + all=0, + timeout='TEST_TIMELIMIT').AndReturn( + (ldap.RES_SEARCH_ENTRY, [test_posix_account], None, [])) + mock_rlo.result3('TEST_RES', + all=0, + timeout='TEST_TIMELIMIT').AndReturn( + (ldap.RES_SEARCH_RESULT, None, None, [])) + + self.mox.StubOutWithMock(ldap, 'ldapobject') + ldap.ldapobject.ReconnectLDAPObject( + uri='TEST_URI', + retry_max='TEST_RETRY_MAX', + retry_delay='TEST_RETRY_DELAY').AndReturn(mock_rlo) + + self.mox.ReplayAll() + + source = ldapsource.LdapSource(config) + data = source.GetPasswdMap() + + self.assertEqual(1, len(data)) + + first = data.PopItem() + + self.assertEqual('/bin/false', first.shell) + def testGetGroupMap(self): test_posix_group = ('cn=test,ou=Group,dc=example,dc=com', {'gidNumber': [1000], diff --git a/nsscache.conf b/nsscache.conf index 41ad263f..298963e0 100644 --- a/nsscache.conf +++ b/nsscache.conf @@ -89,6 +89,9 @@ ldap_filter = (objectclass=posixAccount) # the @example.com domain. Default is no regex. #ldap_groupregex = '' +# Replace all users' shells with the specified one. +#ldap_override_shell='/bin/bash' + # Default uses rfc2307 schema. If rfc2307bis (groups stored as a list of DNs # in 'member' attr), set this to 1 #ldap_rfc2307bis = 0 diff --git a/nsscache.conf.5 b/nsscache.conf.5 index a54909d3..d720a77c 100644 --- a/nsscache.conf.5 +++ b/nsscache.conf.5 @@ -183,6 +183,11 @@ memberOf attributes. All matching groups are concatenated without spaces. For example: '(.*)@example.com' would return a member without the the @example.com domain. Default is no regex. +.TP +.B ldap_override_shell +If specified, set every user's login shell to the given one. May be +useful on bastion hosts or to ensure uniformity. + .TP .B ldap_rfc2307bis Default uses rfc2307 schema. If rfc2307bis (groups stored as a list of DNs