diff --git a/actions/users b/actions/users index 49c214bb3..fcf19197f 100755 --- a/actions/users +++ b/actions/users @@ -68,57 +68,106 @@ def subcommand_pre_install(_): check=True) subprocess.run( ['debconf-set-selections'], - input=b'libnss-ldapd libnss-ldapd/nsswitch multiselect group, passwd, shadow', + input=b'libnss-ldapd libnss-ldapd/nsswitch multiselect ' + b'group, passwd, shadow', check=True) def subcommand_setup(_): """Setup LDAP.""" - # Make sure slapd isn't running when we use slapadd. - action_utils.service_stop('slapd') - subprocess.run(['slapadd'], input=b''' -dn: ou=users,dc=thisbox -objectClass: top -objectClass: organizationalUnit -ou: users - -dn: ou=groups,dc=thisbox -objectClass: top -objectClass: organizationalUnit -ou: groups -''') - action_utils.service_start('slapd') + configure_access_conf() # Update pam configs for access and mkhomedir. subprocess.run(['pam-auth-update', '--package'], check=True) - # Restrict console login to users in admin or sudo group. - with open(ACCESS_CONF, 'r') as conffile: - lines = conffile.readlines() + configure_ldapscripts() - access_conf_completed = False - for line in lines: - if '-:ALL EXCEPT root fbx (admin) (sudo):ALL' in line: - access_conf_completed = True + configure_slapd() - if not access_conf_completed: - with open(ACCESS_CONF, 'a') as conffile: - conffile.write('-:ALL EXCEPT root fbx (admin) (sudo):ALL\n') - # Remove LDAP admin password. Allow root to modify the users directory. - subprocess.run( - ['ldapmodify', '-Y', 'EXTERNAL', '-H', 'ldapi:///'], - input=b''' +def configure_slapd(): + """Configure LDAP authentication and basic structure.""" + was_running = action_utils.service_is_running('slapd') + if not was_running: + action_utils.service_start('slapd') + + try: + setup_admin() + create_organizational_unit('users') + create_organizational_unit('groups') + finally: + if not was_running: + action_utils.service_stop('slapd') + + +def create_organizational_unit(unit): + """Create an organizational unit in LDAP.""" + distinguished_name = 'ou={unit},dc=thisbox'.format(unit=unit) + try: + subprocess.run( + ['ldapsearch', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///', '-s', + 'base', '-b', distinguished_name, '(objectclass=*)'], + stdout=subprocess.DEVNULL, check=True) + return # Already exists + except subprocess.CalledProcessError: + input = ''' +dn: ou={unit},dc=thisbox +objectClass: top +objectClass: organizationalUnit +ou: {unit}'''.format(unit=unit) + subprocess.run(['ldapadd', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///'], + input=input.encode(), stdout=subprocess.DEVNULL, + check=True) + + +def setup_admin(): + """Remove LDAP admin password and Allow root to modify the users.""" + process = subprocess.run( + ['ldapsearch', '-Q', '-L', '-L', '-L', '-Y', 'EXTERNAL', '-H', + 'ldapi:///', '-s', 'base', '-b', 'olcDatabase={1}mdb,cn=config', + '(objectclass=*)', 'olcRootDN', 'olcRootPW'], + check=True, stdout=subprocess.PIPE) + ldap_object = {} + for line in process.stdout.decode().splitlines(): + if line: + line = line.split(':') + ldap_object[line[0]] = line[1] + + if 'olcRootPW' in ldap_object: + subprocess.run( + ['ldapmodify', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///'], + check=True, stdout=subprocess.DEVNULL, input=b''' dn: olcDatabase={1}mdb,cn=config changetype: modify -delete: olcRootPW +delete: olcRootPW''') + root_dn = 'gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth' + if ldap_object['olcRootDN'] != root_dn: + subprocess.run( + ['ldapmodify', '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///'], + check=True, stdout=subprocess.DEVNULL, input=b''' dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcRootDN olcRootDN: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth ''') + +def configure_access_conf(): + """Restrict console login to users in admin or sudo group.""" + with open(ACCESS_CONF, 'r') as conffile: + lines = conffile.readlines() + + for line in lines: + if '-:ALL EXCEPT root fbx (admin) (sudo):ALL' in line: + return + + with open(ACCESS_CONF, 'a') as conffile: + conffile.write('-:ALL EXCEPT root fbx (admin) (sudo):ALL\n') + + +def configure_ldapscripts(): + """Set the configuration used by ldapscripts for later user management.""" aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')