def run(self, *args): from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() existing_perms_raw = ldap.search( "ou=permission,dc=yunohost,dc=org", "(objectclass=permissionYnh)", ["cn"] ) existing_perms = [perm["cn"][0] for perm in existing_perms_raw] # Add SSH and SFTP permissions ldap_map = read_yaml( "/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml" ) if "sftp.main" not in existing_perms: ldap.add( "cn=sftp.main,ou=permission", ldap_map["depends_children"]["cn=sftp.main,ou=permission"], ) if "ssh.main" not in existing_perms: ldap.add( "cn=ssh.main,ou=permission", ldap_map["depends_children"]["cn=ssh.main,ou=permission"], ) # Add a bash terminal to each users users = ldap.search( "ou=users,dc=yunohost,dc=org", filter="(loginShell=*)", attrs=["dn", "uid", "loginShell"], ) for user in users: if user["loginShell"][0] == "/bin/false": dn = user["dn"][0].replace(",dc=yunohost,dc=org", "") ldap.update(dn, {"loginShell": ["/bin/bash"]}) else: user_permission_update( "ssh.main", add=user["uid"][0], sync_perm=False ) permission_sync_to_user() # Somehow this is needed otherwise the PAM thing doesn't forget about the # old loginShell value ? subprocess.call(["nscd", "-i", "passwd"]) if ( "/etc/ssh/sshd_config" in manually_modified_files() and os.system( "grep -q '^ *AllowGroups\\|^ *AllowUsers' /etc/ssh/sshd_config" ) != 0 ): logger.error(m18n.n("diagnosis_sshd_config_insecure"))
def migrate_app_permission(app=None): logger.info(m18n.n("migration_0011_migrate_permission")) apps = _installed_apps() if app: if app not in apps: logger.error( "Can't migrate permission for app %s because it ain't installed..." % app ) apps = [] else: apps = [app] for app in apps: permission = app_setting(app, "allowed_users") path = app_setting(app, "path") domain = app_setting(app, "domain") url = "/" if domain and path else None if permission: known_users = list(user_list()["users"].keys()) allowed = [ user for user in permission.split(",") if user in known_users ] else: allowed = ["all_users"] permission_create( app + ".main", url=url, allowed=allowed, show_tile=True, protected=False, sync_perm=False, ) app_setting(app, "allowed_users", delete=True) # Migrate classic public app still using the legacy unprotected_uris if ( app_setting(app, "unprotected_uris") == "/" or app_setting(app, "skipped_uris") == "/" ): user_permission_update(app + ".main", add="visitors", sync_perm=False) permission_sync_to_user()
def user_group_delete(operation_logger, groupname, force=False, sync_perm=True): """ Delete user Keyword argument: groupname -- Groupname to delete """ from yunohost.permission import permission_sync_to_user from yunohost.utils.ldap import _get_ldap_interface existing_groups = list(user_group_list()["groups"].keys()) if groupname not in existing_groups: raise YunohostValidationError("group_unknown", group=groupname) # Refuse to delete primary groups of a user (e.g. group 'sam' related to user 'sam') # without the force option... # # We also can't delete "all_users" because that's a special group... existing_users = list(user_list()["users"].keys()) undeletable_groups = existing_users + ["all_users", "visitors"] if groupname in undeletable_groups and not force: raise YunohostValidationError("group_cannot_be_deleted", group=groupname) operation_logger.start() ldap = _get_ldap_interface() try: ldap.remove("cn=%s,ou=groups" % groupname) except Exception as e: raise YunohostError("group_deletion_failed", group=groupname, error=e) if sync_perm: permission_sync_to_user() if groupname not in existing_users: logger.success(m18n.n("group_deleted", group=groupname)) else: logger.debug(m18n.n("group_deleted", group=groupname))
def user_group_update(operation_logger, groupname, add=None, remove=None, force=False, sync_perm=True): """ Update user informations Keyword argument: groupname -- Groupname to update add -- User(s) to add in group remove -- User(s) to remove in group """ from yunohost.permission import permission_sync_to_user from yunohost.utils.ldap import _get_ldap_interface existing_users = list(user_list()['users'].keys()) # Refuse to edit a primary group of a user (e.g. group 'sam' related to user 'sam') # Those kind of group should only ever contain the user (e.g. sam) and only this one. # We also can't edit "all_users" without the force option because that's a special group... if not force: if groupname == "all_users": raise YunohostError('group_cannot_edit_all_users') elif groupname == "visitors": raise YunohostError('group_cannot_edit_visitors') elif groupname in existing_users: raise YunohostError('group_cannot_edit_primary_group', group=groupname) # We extract the uid for each member of the group to keep a simple flat list of members current_group = user_group_info(groupname)["members"] new_group = copy.copy(current_group) if add: users_to_add = [add] if not isinstance(add, list) else add for user in users_to_add: if user not in existing_users: raise YunohostError('user_unknown', user=user) if user in current_group: logger.warning( m18n.n('group_user_already_in_group', user=user, group=groupname)) else: operation_logger.related_to.append(('user', user)) new_group += users_to_add if remove: users_to_remove = [remove] if not isinstance(remove, list) else remove for user in users_to_remove: if user not in current_group: logger.warning( m18n.n('group_user_not_in_group', user=user, group=groupname)) else: operation_logger.related_to.append(('user', user)) # Remove users_to_remove from new_group # Kinda like a new_group -= users_to_remove new_group = [u for u in new_group if u not in users_to_remove] new_group_dns = [ "uid=" + user + ",ou=users,dc=yunohost,dc=org" for user in new_group ] if set(new_group) != set(current_group): operation_logger.start() ldap = _get_ldap_interface() try: ldap.update('cn=%s,ou=groups' % groupname, { "member": set(new_group_dns), "memberUid": set(new_group) }) except Exception as e: raise YunohostError('group_update_failed', group=groupname, error=e) if groupname != "all_users": logger.success(m18n.n('group_updated', group=groupname)) else: logger.debug(m18n.n('group_updated', group=groupname)) if sync_perm: permission_sync_to_user() return user_group_info(groupname)
def user_group_create(operation_logger, groupname, gid=None, primary_group=False, sync_perm=True): """ Create group Keyword argument: groupname -- Must be unique """ from yunohost.permission import permission_sync_to_user from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() # Validate uniqueness of groupname in LDAP conflict = ldap.get_conflict({'cn': groupname}, base_dn='ou=groups,dc=yunohost,dc=org') if conflict: raise YunohostError('group_already_exist', group=groupname) # Validate uniqueness of groupname in system group all_existing_groupnames = {x.gr_name for x in grp.getgrall()} if groupname in all_existing_groupnames: if primary_group: logger.warning( m18n.n('group_already_exist_on_system_but_removing_it', group=groupname)) subprocess.check_call("sed --in-place '/^%s:/d' /etc/group" % groupname, shell=True) else: raise YunohostError('group_already_exist_on_system', group=groupname) if not gid: # Get random GID all_gid = {x.gr_gid for x in grp.getgrall()} uid_guid_found = False while not uid_guid_found: gid = str(random.randint(200, 99999)) uid_guid_found = gid not in all_gid attr_dict = { 'objectClass': ['top', 'groupOfNamesYnh', 'posixGroup'], 'cn': groupname, 'gidNumber': gid, } # Here we handle the creation of a primary group # We want to initialize this group to contain the corresponding user # (then we won't be able to add/remove any user in this group) if primary_group: attr_dict["member"] = [ "uid=" + groupname + ",ou=users,dc=yunohost,dc=org" ] operation_logger.start() try: ldap.add('cn=%s,ou=groups' % groupname, attr_dict) except Exception as e: raise YunohostError('group_creation_failed', group=groupname, error=e) if sync_perm: permission_sync_to_user() if not primary_group: logger.success(m18n.n('group_created', group=groupname)) else: logger.debug(m18n.n('group_created', group=groupname)) return {'name': groupname}
def migrate_legacy_permission_settings(app=None): logger.info(m18n.n("migrating_legacy_permission_settings")) apps = _installed_apps() if app: if app not in apps: logger.error( "Can't migrate permission for app %s because it ain't installed..." % app) apps = [] else: apps = [app] for app in apps: settings = _get_app_settings(app) or {} if settings.get("label"): user_permission_update(app + ".main", label=settings["label"], sync_perm=False) del settings["label"] def _setting(name): s = settings.get(name) return s.split(',') if s else [] skipped_urls = [uri for uri in _setting('skipped_uris') if uri != '/'] skipped_urls += ['re:' + regex for regex in _setting('skipped_regex')] unprotected_urls = [ uri for uri in _setting('unprotected_uris') if uri != '/' ] unprotected_urls += [ 're:' + regex for regex in _setting('unprotected_regex') ] protected_urls = [ uri for uri in _setting('protected_uris') if uri != '/' ] protected_urls += [ 're:' + regex for regex in _setting('protected_regex') ] if skipped_urls != []: permission_create(app + ".legacy_skipped_uris", additional_urls=skipped_urls, auth_header=False, label=legacy_permission_label(app, "skipped"), show_tile=False, allowed='visitors', protected=True, sync_perm=False) if unprotected_urls != []: permission_create(app + ".legacy_unprotected_uris", additional_urls=unprotected_urls, auth_header=True, label=legacy_permission_label( app, "unprotected"), show_tile=False, allowed='visitors', protected=True, sync_perm=False) if protected_urls != []: permission_create(app + ".legacy_protected_uris", additional_urls=protected_urls, auth_header=True, label=legacy_permission_label(app, "protected"), show_tile=False, allowed=user_permission_list()['permissions'][ app + ".main"]['allowed'], protected=True, sync_perm=False) legacy_permission_settings = [ "skipped_uris", "unprotected_uris", "protected_uris", "skipped_regex", "unprotected_regex", "protected_regex" ] for key in legacy_permission_settings: if key in settings: del settings[key] _set_app_settings(app, settings) permission_sync_to_user()
def run(self, *args): from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() existing_perms_raw = ldap.search("ou=permission,dc=yunohost,dc=org", "(objectclass=permissionYnh)", ["cn"]) existing_perms = [perm["cn"][0] for perm in existing_perms_raw] # Add SSH and SFTP permissions if "sftp.main" not in existing_perms: ldap.add( "cn=sftp.main,ou=permission", { "cn": "sftp.main", "gidNumber": "5004", "objectClass": ["posixGroup", "permissionYnh"], "groupPermission": [], "authHeader": "FALSE", "label": "SFTP", "showTile": "FALSE", "isProtected": "TRUE", }, ) if "ssh.main" not in existing_perms: ldap.add( "cn=ssh.main,ou=permission", { "cn": "ssh.main", "gidNumber": "5003", "objectClass": ["posixGroup", "permissionYnh"], "groupPermission": [], "authHeader": "FALSE", "label": "SSH", "showTile": "FALSE", "isProtected": "TRUE", }, ) # Add a bash terminal to each users users = ldap.search( "ou=users,dc=yunohost,dc=org", filter="(loginShell=*)", attrs=["dn", "uid", "loginShell"], ) for user in users: if user["loginShell"][0] == "/bin/false": dn = user["dn"][0].replace(",dc=yunohost,dc=org", "") ldap.update(dn, {"loginShell": ["/bin/bash"]}) else: user_permission_update("ssh.main", add=user["uid"][0], sync_perm=False) permission_sync_to_user() # Somehow this is needed otherwise the PAM thing doesn't forget about the # old loginShell value ? subprocess.call(["nscd", "-i", "passwd"]) if ("/etc/ssh/sshd_config" in manually_modified_files() and os.system( "grep -q '^ *AllowGroups\\|^ *AllowUsers' /etc/ssh/sshd_config" ) != 0): logger.error(m18n.n("diagnosis_sshd_config_insecure"))