From 5e6bcb2346e89864437331b5ce4248f4e0983cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josu=C3=A9=20Tille?= Date: Fri, 28 Dec 2018 14:23:12 +0100 Subject: [PATCH 01/28] Add possibility to restrict the user allowed to access by sftp --- data/actionsmap/yunohost.yml | 15 +++++++++++++++ data/hooks/conf_regen/03-ssh | 1 + data/templates/ssh/sshd_config | 26 +++++++++++++++++++------- locales/en.json | 2 ++ src/yunohost/ssh.py | 28 ++++++++++++++++++++++++++++ src/yunohost/user.py | 6 ++++++ 6 files changed, 71 insertions(+), 7 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index fb569dcd0..4f9f608bb 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -408,6 +408,21 @@ user: key: help: The key to be removed + ### user_ssh_enable_permission() + enable-permission: + action_help: Enable sftp permission + api: POST /users/ssh/sftp/enable + configuration: + authenticate: all + authenticator: as-root + + ### user_ssh_disable_permission() + disable-permission: + action_help: Disable sftp permission + api: POST /users/ssh/sftp/disable + configuration: + authenticate: all + authenticator: as-root ############################# # Domain # diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 54b7c55b7..76a894ccf 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -28,6 +28,7 @@ do_pre_regen() { export ssh_keys export ipv6_enabled + export sftp_secure ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" } diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index 84f06d4e5..bb6520e64 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -64,21 +64,33 @@ PrintLastLog yes ClientAliveInterval 60 AcceptEnv LANG LC_* +# Disallow user without ssh or sftp permissions +AllowGroups ssh.main sftp.main admins root + +# Allow users to create tunnels or forwarding +AllowTcpForwarding yes +AllowStreamLocalForwarding yes +PermitTunnel yes +PermitUserRC yes + # SFTP stuff Subsystem sftp internal-sftp -# Forbid users from using their account SSH as a VPN (even if SSH login is disabled) +# Apply following instructions to user with sftp perm only +Match Group sftp.main,!ssh.main +ForceCommand internal-sftp +# We currently are not able to restrict /home/USER +# So we chroot only on /home +# See https://serverfault.com/questions/584986/bad-ownership-or-modes-for-chroot-directory-component +#ChrootDirectory /home/%u +ChrootDirectory /home +# Forbid SFTP users from using their account SSH as a VPN (even if SSH login is disabled) AllowTcpForwarding no AllowStreamLocalForwarding no - +PermitTunnel no # Disable .ssh/rc, which could be edited (e.g. from Nextcloud or whatever) by users to execute arbitrary commands even if SSH login is disabled PermitUserRC no -Match User admin,root - AllowTcpForwarding yes - AllowStreamLocalForwarding yes - PermitUserRC yes - # root login is allowed on local networks # It's meant to be a backup solution in case LDAP is down and diff --git a/locales/en.json b/locales/en.json index 8510cdf58..a08855ce2 100644 --- a/locales/en.json +++ b/locales/en.json @@ -585,6 +585,8 @@ "service_unknown": "Unknown service '{service:s}'", "show_tile_cant_be_enabled_for_url_not_defined": "You cannot enable 'show_tile' right now, because you must first define an URL for the permission '{permission}'", "show_tile_cant_be_enabled_for_regex": "You cannot enable 'show_tile' right no, because the URL for the permission '{permission}' is a regex", + "sftp_permission_already_disabled": "SFTP permission already disabled", + "sftp_permission_already_enabled": "SFTP permission already enabled", "ssowat_conf_generated": "SSOwat configuration regenerated", "ssowat_conf_updated": "SSOwat configuration updated", "system_upgraded": "System upgraded", diff --git a/src/yunohost/ssh.py b/src/yunohost/ssh.py index be876ce16..eb4cc2702 100644 --- a/src/yunohost/ssh.py +++ b/src/yunohost/ssh.py @@ -6,10 +6,13 @@ import pwd import subprocess from yunohost.utils.error import YunohostError +from moulinette import m18n +from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir SSHD_CONFIG_PATH = "/etc/ssh/sshd_config" +logger = getActionLogger('yunohost.user') def user_ssh_allow(username): """ @@ -147,6 +150,31 @@ def user_ssh_remove_key(username, key): write_to_file(authorized_keys_file, authorized_keys_content) + +def user_ssh_enable_permission(auth): + """ + Enable the permission for sftp. When disabled all user are allowed to access by sftp. + + """ + from permission import permission_add, user_permission_list + + if user_permission_list(auth, app="sftp", permission="main")['permissions']: + logger.warning(m18n.n('sftp_permission_already_enabled')) + else: + permission_add(auth, "sftp", "main") + +def user_ssh_disable_permission(auth): + """ + Diable the permission for sftp. When disabled all user are allowed to access by sftp. + + """ + from permission import permission_remove, user_permission_list + + if user_permission_list(auth, app="sftp", permission="main")['permissions']: + permission_remove(auth, "sftp", "main", force=True) + else: + logger.warning(m18n.n('sftp_permission_already_disabled')) + # # Helpers # diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 67fd43a03..50b352d61 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -816,6 +816,12 @@ def user_ssh_add_key(username, key, comment): def user_ssh_remove_key(username, key): return yunohost.ssh.user_ssh_remove_key(username, key) +def user_ssh_enable_permission(auth): + return yunohost.ssh.user_ssh_enable_permission(auth) + +def user_ssh_disable_permission(auth): + return yunohost.ssh.user_ssh_disable_permission(auth) + # # End SSH subcategory # From f79b0ff0a3954b9d29c9b93e5146c9d56b8b6201 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 23 Sep 2020 05:00:09 +0200 Subject: [PATCH 02/28] [enh] SFTP and SSH permissions --- data/actionsmap/yunohost.yml | 16 ----- data/hooks/conf_regen/03-ssh | 1 - data/other/ldap_scheme.yml | 21 ++++++ data/templates/ssh/sshd_config | 1 - locales/en.json | 2 +- .../0019_ssh_sftp_permissions.py | 56 +++++++++++++++ src/yunohost/ssh.py | 70 ------------------- src/yunohost/user.py | 6 -- 8 files changed, 78 insertions(+), 95 deletions(-) create mode 100644 src/yunohost/data_migrations/0019_ssh_sftp_permissions.py diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 4f9f608bb..afe595723 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -408,22 +408,6 @@ user: key: help: The key to be removed - ### user_ssh_enable_permission() - enable-permission: - action_help: Enable sftp permission - api: POST /users/ssh/sftp/enable - configuration: - authenticate: all - authenticator: as-root - - ### user_ssh_disable_permission() - disable-permission: - action_help: Disable sftp permission - api: POST /users/ssh/sftp/disable - configuration: - authenticate: all - authenticator: as-root - ############################# # Domain # ############################# diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 76a894ccf..54b7c55b7 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -28,7 +28,6 @@ do_pre_regen() { export ssh_keys export ipv6_enabled - export sftp_secure ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" } diff --git a/data/other/ldap_scheme.yml b/data/other/ldap_scheme.yml index aa2b46ad3..ba678f1f8 100644 --- a/data/other/ldap_scheme.yml +++ b/data/other/ldap_scheme.yml @@ -89,3 +89,24 @@ depends_children: label: "XMPP" showTile: "FALSE" isProtected: "TRUE" + cn=ssh.main,ou=permission: + cn: ssh.main + gidNumber: "5003" + objectClass: + - posixGroup + - permissionYnh + groupPermission: [] + cn=ssh.tunnel,ou=permission: + cn: ssh.tunnel + gidNumber: "5004" + objectClass: + - posixGroup + - permissionYnh + groupPermission: [] + cn=sftp.main,ou=permission: + cn: sftp.main + gidNumber: "5005" + objectClass: + - posixGroup + - permissionYnh + groupPermission: [] diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index bb6520e64..709483728 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -91,7 +91,6 @@ PermitTunnel no # Disable .ssh/rc, which could be edited (e.g. from Nextcloud or whatever) by users to execute arbitrary commands even if SSH login is disabled PermitUserRC no - # root login is allowed on local networks # It's meant to be a backup solution in case LDAP is down and # user admin can't be used... diff --git a/locales/en.json b/locales/en.json index a08855ce2..a23441382 100644 --- a/locales/en.json +++ b/locales/en.json @@ -587,7 +587,7 @@ "show_tile_cant_be_enabled_for_regex": "You cannot enable 'show_tile' right no, because the URL for the permission '{permission}' is a regex", "sftp_permission_already_disabled": "SFTP permission already disabled", "sftp_permission_already_enabled": "SFTP permission already enabled", - "ssowat_conf_generated": "SSOwat configuration regenerated", + "ssowat_conf_generated": "SSOwat configuration generated", "ssowat_conf_updated": "SSOwat configuration updated", "system_upgraded": "System upgraded", "system_username_exists": "Username already exists in the list of system users", diff --git a/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py new file mode 100644 index 000000000..fc970bd56 --- /dev/null +++ b/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py @@ -0,0 +1,56 @@ +import time +import subprocess + +from moulinette import m18n +from yunohost.utils.error import YunohostError +from moulinette.utils.log import getActionLogger +from moulinette.utils.filesystem import read_yaml + +from yunohost.tools import Migration +from yunohost.permission import user_permission_update + +logger = getActionLogger('yunohost.migration') + +################################################### +# Tools used also for restoration +################################################### + + +class MyMigration(Migration): + """ + Add new permissions around SSH/SFTP features + """ + + required = True + + def run(self): + logger.info(m18n.n("migration_0019_ssh_sftp_permissions")) + + from yunohost.utils.ldap import _get_ldap_interface + ldap = _get_ldap_interface() + + add_perm_to_users = False + + # Add SSH and SFTP permissions + ldap_map = read_yaml('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml') + for rdn, attr_dict in ldap_map['depends_children'].items(): + try: + objects = ldap.search(rdn + ",dc=yunohost,dc=org") + # ldap search will raise an exception if no corresponding object is found >.> ... + except Exception as e: + if rdn == "cn=ssh.main,ou=permission": + add_perm_to_users = True + ldap.add(rdn, attr_dict) + + # 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']}) + elif add_perm_to_users: + user_permission_update("ssh.main", add=user["uid"][0], sync_perm=False) + + # Somehow this is needed otherwise the PAM thing doesn't forget about the + # old loginShell value ? + subprocess.call(['nscd', '-i', 'passwd']) diff --git a/src/yunohost/ssh.py b/src/yunohost/ssh.py index eb4cc2702..9122cf1d6 100644 --- a/src/yunohost/ssh.py +++ b/src/yunohost/ssh.py @@ -6,55 +6,10 @@ import pwd import subprocess from yunohost.utils.error import YunohostError -from moulinette import m18n -from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir SSHD_CONFIG_PATH = "/etc/ssh/sshd_config" -logger = getActionLogger('yunohost.user') - -def user_ssh_allow(username): - """ - Allow YunoHost user connect as ssh. - - Keyword argument: - username -- User username - """ - # TODO it would be good to support different kind of shells - - if not _get_user_for_ssh(username): - raise YunohostError('user_unknown', user=username) - - from yunohost.utils.ldap import _get_ldap_interface - ldap = _get_ldap_interface() - ldap.update('uid=%s,ou=users' % username, {'loginShell': ['/bin/bash']}) - - # Somehow this is needed otherwise the PAM thing doesn't forget about the - # old loginShell value ? - subprocess.call(['nscd', '-i', 'passwd']) - - -def user_ssh_disallow(username): - """ - Disallow YunoHost user connect as ssh. - - Keyword argument: - username -- User username - """ - # TODO it would be good to support different kind of shells - - if not _get_user_for_ssh(username): - raise YunohostError('user_unknown', user=username) - - from yunohost.utils.ldap import _get_ldap_interface - ldap = _get_ldap_interface() - ldap.update('uid=%s,ou=users' % username, {'loginShell': ['/bin/false']}) - - # Somehow this is needed otherwise the PAM thing doesn't forget about the - # old loginShell value ? - subprocess.call(['nscd', '-i', 'passwd']) - def user_ssh_list_keys(username): user = _get_user_for_ssh(username, ["homeDirectory"]) @@ -150,31 +105,6 @@ def user_ssh_remove_key(username, key): write_to_file(authorized_keys_file, authorized_keys_content) - -def user_ssh_enable_permission(auth): - """ - Enable the permission for sftp. When disabled all user are allowed to access by sftp. - - """ - from permission import permission_add, user_permission_list - - if user_permission_list(auth, app="sftp", permission="main")['permissions']: - logger.warning(m18n.n('sftp_permission_already_enabled')) - else: - permission_add(auth, "sftp", "main") - -def user_ssh_disable_permission(auth): - """ - Diable the permission for sftp. When disabled all user are allowed to access by sftp. - - """ - from permission import permission_remove, user_permission_list - - if user_permission_list(auth, app="sftp", permission="main")['permissions']: - permission_remove(auth, "sftp", "main", force=True) - else: - logger.warning(m18n.n('sftp_permission_already_disabled')) - # # Helpers # diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 50b352d61..67fd43a03 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -816,12 +816,6 @@ def user_ssh_add_key(username, key, comment): def user_ssh_remove_key(username, key): return yunohost.ssh.user_ssh_remove_key(username, key) -def user_ssh_enable_permission(auth): - return yunohost.ssh.user_ssh_enable_permission(auth) - -def user_ssh_disable_permission(auth): - return yunohost.ssh.user_ssh_disable_permission(auth) - # # End SSH subcategory # From aa9b8318e781822c899b071ab447a1bbd643547a Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 23 Sep 2020 05:37:17 +0200 Subject: [PATCH 03/28] [fix] pep8 --- src/yunohost/data_migrations/0019_ssh_sftp_permissions.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py index fc970bd56..b682c77d2 100644 --- a/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py @@ -1,8 +1,6 @@ -import time import subprocess from moulinette import m18n -from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_yaml @@ -35,9 +33,9 @@ class MyMigration(Migration): ldap_map = read_yaml('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml') for rdn, attr_dict in ldap_map['depends_children'].items(): try: - objects = ldap.search(rdn + ",dc=yunohost,dc=org") + ldap.search(rdn + ",dc=yunohost,dc=org") # ldap search will raise an exception if no corresponding object is found >.> ... - except Exception as e: + except Exception: if rdn == "cn=ssh.main,ou=permission": add_perm_to_users = True ldap.add(rdn, attr_dict) From 2db6fbda692b683d563dc675aac09e4028abe982 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 23 Sep 2020 05:44:18 +0200 Subject: [PATCH 04/28] [fix] Remove specific ssh tunnel perm --- data/other/ldap_scheme.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/data/other/ldap_scheme.yml b/data/other/ldap_scheme.yml index ba678f1f8..b6d83e5df 100644 --- a/data/other/ldap_scheme.yml +++ b/data/other/ldap_scheme.yml @@ -96,17 +96,10 @@ depends_children: - posixGroup - permissionYnh groupPermission: [] - cn=ssh.tunnel,ou=permission: - cn: ssh.tunnel + cn=sftp.main,ou=permission: + cn: sftp.main gidNumber: "5004" objectClass: - posixGroup - permissionYnh groupPermission: [] - cn=sftp.main,ou=permission: - cn: sftp.main - gidNumber: "5005" - objectClass: - - posixGroup - - permissionYnh - groupPermission: [] From 32fcbea757b2bf26b2008e6c024ee4985886664f Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 23 Sep 2020 05:47:10 +0200 Subject: [PATCH 05/28] [fix] Remove old ssh allow method --- src/yunohost/user.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 67fd43a03..b2dd79989 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -797,14 +797,6 @@ def user_permission_info(permission): import yunohost.ssh -def user_ssh_allow(username): - return yunohost.ssh.user_ssh_allow(username) - - -def user_ssh_disallow(username): - return yunohost.ssh.user_ssh_disallow(username) - - def user_ssh_list_keys(username): return yunohost.ssh.user_ssh_list_keys(username) From cd5798763c854ee16e864d9ab0ed05bc7588ad25 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Thu, 3 Dec 2020 18:00:57 +0100 Subject: [PATCH 06/28] [fix] No new line --- data/other/ldap_scheme.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data/other/ldap_scheme.yml b/data/other/ldap_scheme.yml index b6d83e5df..b45b3ac3a 100644 --- a/data/other/ldap_scheme.yml +++ b/data/other/ldap_scheme.yml @@ -96,6 +96,10 @@ depends_children: - posixGroup - permissionYnh groupPermission: [] + authHeader: "FALSE" + label: "SSH" + showTile: "FALSE" + isProtected: "TRUE" cn=sftp.main,ou=permission: cn: sftp.main gidNumber: "5004" @@ -103,3 +107,7 @@ depends_children: - posixGroup - permissionYnh groupPermission: [] + authHeader: "FALSE" + label: "SFTP" + showTile: "FALSE" + isProtected: "TRUE" From 95eea93c4a6ec3184d5255ddae39e2416b2d701d Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 18:27:09 +0100 Subject: [PATCH 07/28] [fix] Remove rebase conflict blank line --- data/hooks/conf_regen/03-ssh | 1 - data/templates/ssh/sshd_config | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 54b7c55b7..a8fe661e5 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -25,7 +25,6 @@ do_pre_regen() { # Support different strategy for security configurations export compatibility="$(yunohost settings get 'security.ssh.compatibility')" - export ssh_keys export ipv6_enabled ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index 709483728..bb6520e64 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -91,6 +91,7 @@ PermitTunnel no # Disable .ssh/rc, which could be edited (e.g. from Nextcloud or whatever) by users to execute arbitrary commands even if SSH login is disabled PermitUserRC no + # root login is allowed on local networks # It's meant to be a backup solution in case LDAP is down and # user admin can't be used... From 0f67278afe05b60fca18d270d3e6fb33149e9302 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 18:32:21 +0100 Subject: [PATCH 08/28] [fix] Rename migrations --- src/yunohost/data_migrations/0019_ssh_sftp_permissions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py index b682c77d2..cd4f4c765 100644 --- a/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py @@ -22,7 +22,7 @@ class MyMigration(Migration): required = True def run(self): - logger.info(m18n.n("migration_0019_ssh_sftp_permissions")) + logger.info(m18n.n("migration_0020_ssh_sftp_permissions")) from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() From 0e8cc1851de0893e20e316051fccc1199fc4eb74 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 18:32:36 +0100 Subject: [PATCH 09/28] [fix] Rename migrations --- ...{0019_ssh_sftp_permissions.py => 0020_ssh_sftp_permissions.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/yunohost/data_migrations/{0019_ssh_sftp_permissions.py => 0020_ssh_sftp_permissions.py} (100%) diff --git a/src/yunohost/data_migrations/0019_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py similarity index 100% rename from src/yunohost/data_migrations/0019_ssh_sftp_permissions.py rename to src/yunohost/data_migrations/0020_ssh_sftp_permissions.py From 8ca092d984522805ab25fdac8ffeaf3f9add051d Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 18:39:08 +0100 Subject: [PATCH 10/28] [fix] Remove old command --- data/actionsmap/yunohost.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index afe595723..19a1c1c92 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -351,25 +351,6 @@ user: ssh: subcategory_help: Manage ssh access actions: - ### user_ssh_enable() - allow: - action_help: Allow the user to uses ssh - api: POST /users/ssh/enable - arguments: - username: - help: Username of the user - extra: - pattern: *pattern_username - - ### user_ssh_disable() - disallow: - action_help: Disallow the user to uses ssh - api: POST /users/ssh/disable - arguments: - username: - help: Username of the user - extra: - pattern: *pattern_username ### user_ssh_keys_list() list-keys: From f3db1c99aa1818e15f9833f7253b0034e5893954 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 18:42:22 +0100 Subject: [PATCH 11/28] [fix] Small residual rebase conflict --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index a23441382..57f323525 100644 --- a/locales/en.json +++ b/locales/en.json @@ -585,9 +585,9 @@ "service_unknown": "Unknown service '{service:s}'", "show_tile_cant_be_enabled_for_url_not_defined": "You cannot enable 'show_tile' right now, because you must first define an URL for the permission '{permission}'", "show_tile_cant_be_enabled_for_regex": "You cannot enable 'show_tile' right no, because the URL for the permission '{permission}' is a regex", + "ssowat_conf_generated": "SSOwat configuration regenerated", "sftp_permission_already_disabled": "SFTP permission already disabled", "sftp_permission_already_enabled": "SFTP permission already enabled", - "ssowat_conf_generated": "SSOwat configuration generated", "ssowat_conf_updated": "SSOwat configuration updated", "system_upgraded": "System upgraded", "system_username_exists": "Username already exists in the list of system users", From dec4b252756650cfe20c82881d7b7822b306d6be Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 19:49:52 +0100 Subject: [PATCH 12/28] [fix] Missing description keys --- locales/en.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/locales/en.json b/locales/en.json index 57f323525..c625baf14 100644 --- a/locales/en.json +++ b/locales/en.json @@ -418,6 +418,7 @@ "migration_description_0017_postgresql_9p6_to_11": "Migrate databases from PostgreSQL 9.6 to 11", "migration_description_0018_xtable_to_nftable": "Migrate old network traffic rules to the new nftable system", "migration_description_0019_extend_permissions_features": "Extend/rework the app permission management system", + "migration_description_0020_ssh_sftp_permissions": "Add SSH and SFTP permissions support", "migration_0011_create_group": "Creating a group for each user...", "migration_0011_LDAP_update_failed": "Unable to update LDAP. Error: {error:s}", "migration_0011_migrate_permission": "Migrating permissions from apps settings to LDAP...", @@ -449,6 +450,7 @@ "migration_0019_migration_failed_trying_to_rollback": "Could not migrate... trying to roll back the system.", "migration_0019_rollback_success": "System rolled back.", "migration_0019_slapd_config_will_be_overwritten": "It looks like you manually edited the slapd configuration. For this critical migration, YunoHost needs to force the update of the slapd configuration. The original files will be backuped in {conf_backup_folder}.", + "migration_0020_ssh_sftp_permissions": "SSH/SFTP permissions", "migrations_already_ran": "Those migrations are already done: {ids}", "migrations_cant_reach_migration_file": "Could not access migrations files at the path '%s'", "migrations_dependencies_not_satisfied": "Run these migrations: '{dependencies_id}', before migration {id}.", From 14ff5cf4fc7c1784cc1a71c7fb14cc1db7f5b6c4 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 19:50:44 +0100 Subject: [PATCH 13/28] [fix] Remove unused i18n keys --- locales/en.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index c625baf14..c03236302 100644 --- a/locales/en.json +++ b/locales/en.json @@ -588,8 +588,6 @@ "show_tile_cant_be_enabled_for_url_not_defined": "You cannot enable 'show_tile' right now, because you must first define an URL for the permission '{permission}'", "show_tile_cant_be_enabled_for_regex": "You cannot enable 'show_tile' right no, because the URL for the permission '{permission}' is a regex", "ssowat_conf_generated": "SSOwat configuration regenerated", - "sftp_permission_already_disabled": "SFTP permission already disabled", - "sftp_permission_already_enabled": "SFTP permission already enabled", "ssowat_conf_updated": "SSOwat configuration updated", "system_upgraded": "System upgraded", "system_username_exists": "Username already exists in the list of system users", From efcf5e1ceb8b64702b680c864875a7c5f924eef5 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 3 Dec 2020 22:25:58 +0100 Subject: [PATCH 14/28] [fix] Unsuded import --- src/yunohost/ssh.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/yunohost/ssh.py b/src/yunohost/ssh.py index 9122cf1d6..0c69d9083 100644 --- a/src/yunohost/ssh.py +++ b/src/yunohost/ssh.py @@ -3,9 +3,7 @@ import re import os import pwd -import subprocess -from yunohost.utils.error import YunohostError from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir SSHD_CONFIG_PATH = "/etc/ssh/sshd_config" From fb1fddd07ec97240aef9619a79bbe261a730435a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Mar 2021 14:59:47 +0100 Subject: [PATCH 15/28] To be consistent with migration 0020, all new users should have /bin/bash as terminal, also we probably don't care about fetching loginShell anymore --- src/yunohost/ssh.py | 4 ---- src/yunohost/tests/test_apps_arguments_parsing.py | 10 ---------- src/yunohost/user.py | 11 ++--------- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/src/yunohost/ssh.py b/src/yunohost/ssh.py index 428b70ea3..0e20737d0 100644 --- a/src/yunohost/ssh.py +++ b/src/yunohost/ssh.py @@ -151,8 +151,6 @@ def _get_user_for_ssh(username, attrs=None): "username": "root", "fullname": "", "mail": "", - "ssh_allowed": ssh_root_login_status()["PermitRootLogin"], - "shell": root_unix.pw_shell, "home_path": root_unix.pw_dir, } @@ -162,8 +160,6 @@ def _get_user_for_ssh(username, attrs=None): "username": "admin", "fullname": "", "mail": "", - "ssh_allowed": admin_unix.pw_shell.strip() != "/bin/false", - "shell": admin_unix.pw_shell, "home_path": admin_unix.pw_dir, } diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index 98dd280ff..95d1548ae 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -1206,7 +1206,6 @@ def test_parse_args_in_yunohost_format_user_empty(): "some_user": { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "p@ynh.local", "fullname": "the first name the last name", @@ -1232,7 +1231,6 @@ def test_parse_args_in_yunohost_format_user(): username: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "p@ynh.local", "fullname": "the first name the last name", @@ -1261,7 +1259,6 @@ def test_parse_args_in_yunohost_format_user_two_users(): username: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "p@ynh.local", "fullname": "the first name the last name", @@ -1269,7 +1266,6 @@ def test_parse_args_in_yunohost_format_user_two_users(): other_user: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "z@ynh.local", "fullname": "john doe", @@ -1304,7 +1300,6 @@ def test_parse_args_in_yunohost_format_user_two_users_wrong_answer(): username: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "p@ynh.local", "fullname": "the first name the last name", @@ -1312,7 +1307,6 @@ def test_parse_args_in_yunohost_format_user_two_users_wrong_answer(): other_user: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "z@ynh.local", "fullname": "john doe", @@ -1339,7 +1333,6 @@ def test_parse_args_in_yunohost_format_user_two_users_no_default(): username: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "p@ynh.local", "fullname": "the first name the last name", @@ -1347,7 +1340,6 @@ def test_parse_args_in_yunohost_format_user_two_users_no_default(): other_user: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "z@ynh.local", "fullname": "john doe", @@ -1369,7 +1361,6 @@ def test_parse_args_in_yunohost_format_user_two_users_default_input(): username: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "p@ynh.local", "fullname": "the first name the last name", @@ -1377,7 +1368,6 @@ def test_parse_args_in_yunohost_format_user_two_users_default_input(): other_user: { "ssh_allowed": False, "username": "some_user", - "shell": "/bin/false", "mailbox-quota": "0", "mail": "z@ynh.local", "fullname": "john doe", diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 4098092e5..455c71139 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -53,7 +53,6 @@ def user_list(fields=None): "cn": "fullname", "mail": "mail", "maildrop": "mail-forward", - "loginShell": "shell", "homeDirectory": "home_path", "mailuserquota": "mailbox-quota", } @@ -69,7 +68,7 @@ def user_list(fields=None): else: raise YunohostError("field_invalid", attr) else: - attrs = ["uid", "cn", "mail", "mailuserquota", "loginShell"] + attrs = ["uid", "cn", "mail", "mailuserquota"] ldap = _get_ldap_interface() result = ldap.search( @@ -82,12 +81,6 @@ def user_list(fields=None): entry = {} for attr, values in user.items(): if values: - if attr == "loginShell": - if values[0].strip() == "/bin/false": - entry["ssh_allowed"] = False - else: - entry["ssh_allowed"] = True - entry[user_attrs[attr]] = values[0] uid = entry[user_attrs["uid"]] @@ -206,7 +199,7 @@ def user_create( "gidNumber": [uid], "uidNumber": [uid], "homeDirectory": ["/home/" + username], - "loginShell": ["/bin/false"], + "loginShell": ["/bin/bash"], } # If it is the first user, add some aliases From f158a4da9e78050820903ecda0b6f5ac42d801bd Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Mar 2021 16:10:00 +0100 Subject: [PATCH 16/28] Use YunohostValidationError instead of raw Exceptions --- src/yunohost/ssh.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/yunohost/ssh.py b/src/yunohost/ssh.py index 0e20737d0..e2ecaeef3 100644 --- a/src/yunohost/ssh.py +++ b/src/yunohost/ssh.py @@ -13,7 +13,7 @@ SSHD_CONFIG_PATH = "/etc/ssh/sshd_config" def user_ssh_list_keys(username): user = _get_user_for_ssh(username, ["homeDirectory"]) if not user: - raise Exception("User with username '%s' doesn't exists" % username) + raise YunohostValidationError("user_unknown", user=username) authorized_keys_file = os.path.join( user["homeDirectory"][0], ".ssh", "authorized_keys" @@ -50,7 +50,7 @@ def user_ssh_list_keys(username): def user_ssh_add_key(username, key, comment): user = _get_user_for_ssh(username, ["homeDirectory", "uid"]) if not user: - raise Exception("User with username '%s' doesn't exists" % username) + raise YunohostValidationError("user_unknown", user=username) authorized_keys_file = os.path.join( user["homeDirectory"][0], ".ssh", "authorized_keys" @@ -90,21 +90,26 @@ def user_ssh_add_key(username, key, comment): def user_ssh_remove_key(username, key): user = _get_user_for_ssh(username, ["homeDirectory", "uid"]) if not user: - raise Exception("User with username '%s' doesn't exists" % username) + raise YunohostValidationError("user_unknown", user=username) authorized_keys_file = os.path.join( user["homeDirectory"][0], ".ssh", "authorized_keys" ) if not os.path.exists(authorized_keys_file): - raise Exception( - "this key doesn't exists ({} dosesn't exists)".format(authorized_keys_file) + raise YunohostValidationError( + "this key doesn't exists ({} dosesn't exists)".format(authorized_keys_file), + raw_msg=True ) authorized_keys_content = read_file(authorized_keys_file) if key not in authorized_keys_content: - raise Exception("Key '{}' is not present in authorized_keys".format(key)) + raise YunohostValidationError( + "Key '{}' is not present in authorized_keys".format(key), + raw_msg=True + ) + # don't delete the previous comment because we can't verify if it's legit From b40f21458f82c3c9fc3619ac9593f6cca7f6ba73 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 25 Mar 2021 16:19:40 +0100 Subject: [PATCH 17/28] ssh config: indent, misc readabilty improvements --- data/templates/ssh/sshd_config | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index bb6520e64..28e424aa8 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -78,18 +78,17 @@ Subsystem sftp internal-sftp # Apply following instructions to user with sftp perm only Match Group sftp.main,!ssh.main -ForceCommand internal-sftp -# We currently are not able to restrict /home/USER -# So we chroot only on /home -# See https://serverfault.com/questions/584986/bad-ownership-or-modes-for-chroot-directory-component -#ChrootDirectory /home/%u -ChrootDirectory /home -# Forbid SFTP users from using their account SSH as a VPN (even if SSH login is disabled) -AllowTcpForwarding no -AllowStreamLocalForwarding no -PermitTunnel no -# Disable .ssh/rc, which could be edited (e.g. from Nextcloud or whatever) by users to execute arbitrary commands even if SSH login is disabled -PermitUserRC no + ForceCommand internal-sftp + # We can't restrict to /home/%u because the chroot base must be owned by root + # So we chroot only on /home + # See https://serverfault.com/questions/584986/bad-ownership-or-modes-for-chroot-directory-component + ChrootDirectory /home + # Forbid SFTP users from using their account SSH as a VPN (even if SSH login is disabled) + AllowTcpForwarding no + AllowStreamLocalForwarding no + PermitTunnel no + # Disable .ssh/rc, which could be edited (e.g. from Nextcloud or whatever) by users to execute arbitrary commands even if SSH login is disabled + PermitUserRC no # root login is allowed on local networks @@ -98,4 +97,4 @@ PermitUserRC no # If the server is a VPS, it's expected that the owner of the # server has access to a web console through which to log in. Match Address 192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,169.254.0.0/16,fe80::/10,fd00::/8 - PermitRootLogin yes + PermitRootLogin yes From ce946cc0b0c989204070b5bafa5ecb53912b2317 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Apr 2021 19:12:19 +0200 Subject: [PATCH 18/28] Introduce a decorator to automatically backup/rollback ldap db during ldap-related migrations --- locales/en.json | 8 +-- .../0019_extend_permissions_features.py | 57 ++----------------- .../0020_ssh_sftp_permissions.py | 5 +- src/yunohost/tools.py | 40 +++++++++++++ 4 files changed, 52 insertions(+), 58 deletions(-) diff --git a/locales/en.json b/locales/en.json index d17ff1f91..4c731863d 100644 --- a/locales/en.json +++ b/locales/en.json @@ -420,6 +420,10 @@ "migration_description_0018_xtable_to_nftable": "Migrate old network traffic rules to the new nftable system", "migration_description_0019_extend_permissions_features": "Extend/rework the app permission management system", "migration_description_0020_ssh_sftp_permissions": "Add SSH and SFTP permissions support", + "migration_ldap_backup_before_migration": "Creating a backup of LDAP database and apps settings prior to the actual migration.", + "migration_ldap_can_not_backup_before_migration": "The backup of the system could not be completed before the migration failed. Error: {error:s}", + "migration_ldap_migration_failed_trying_to_rollback": "Could not migrate... trying to roll back the system.", + "migration_ldap_rollback_success": "System rolled back.", "migration_0011_create_group": "Creating a group for each user...", "migration_0011_LDAP_update_failed": "Unable to update LDAP. Error: {error:s}", "migration_0011_migrate_permission": "Migrating permissions from apps settings to LDAP...", @@ -446,10 +450,6 @@ "migration_0018_failed_to_migrate_iptables_rules": "Failed to migrate legacy iptables rules to nftables: {error}", "migration_0018_failed_to_reset_legacy_rules": "Failed to reset legacy iptables rules: {error}", "migration_0019_add_new_attributes_in_ldap": "Add new attributes for permissions in LDAP database", - "migration_0019_backup_before_migration": "Creating a backup of LDAP database and apps settings prior to the actual migration.", - "migration_0019_can_not_backup_before_migration": "The backup of the system could not be completed before the migration failed. Error: {error:s}", - "migration_0019_migration_failed_trying_to_rollback": "Could not migrate... trying to roll back the system.", - "migration_0019_rollback_success": "System rolled back.", "migration_0019_slapd_config_will_be_overwritten": "It looks like you manually edited the slapd configuration. For this critical migration, YunoHost needs to force the update of the slapd configuration. The original files will be backuped in {conf_backup_folder}.", "migration_0020_ssh_sftp_permissions": "SSH/SFTP permissions", "migrations_already_ran": "Those migrations are already done: {ids}", diff --git a/src/yunohost/data_migrations/0019_extend_permissions_features.py b/src/yunohost/data_migrations/0019_extend_permissions_features.py index 07f740a2b..30ae01ae4 100644 --- a/src/yunohost/data_migrations/0019_extend_permissions_features.py +++ b/src/yunohost/data_migrations/0019_extend_permissions_features.py @@ -17,8 +17,6 @@ class MyMigration(Migration): Add protected attribute in LDAP permission """ - required = True - def add_new_ldap_attributes(self): from yunohost.utils.ldap import _get_ldap_interface @@ -78,54 +76,11 @@ class MyMigration(Migration): ldap.update("cn=%s,ou=permission" % permission, update) - def run(self): + @ldap_migration + def run(self, backup_folder): - # FIXME : what do we really want to do here ... - # Imho we should just force-regen the conf in all case, and maybe - # just display a warning if we detect that the conf was manually modified + # Update LDAP database + self.add_new_ldap_attributes() - # Backup LDAP and the apps settings before to do the migration - logger.info(m18n.n("migration_0019_backup_before_migration")) - try: - backup_folder = "/home/yunohost.backup/premigration/" + time.strftime( - "%Y%m%d-%H%M%S", time.gmtime() - ) - os.makedirs(backup_folder, 0o750) - os.system("systemctl stop slapd") - os.system("cp -r --preserve /etc/ldap %s/ldap_config" % backup_folder) - os.system("cp -r --preserve /var/lib/ldap %s/ldap_db" % backup_folder) - os.system( - "cp -r --preserve /etc/yunohost/apps %s/apps_settings" % backup_folder - ) - except Exception as e: - raise YunohostError( - "migration_0019_can_not_backup_before_migration", error=e - ) - finally: - os.system("systemctl start slapd") - - try: - # Update LDAP database - self.add_new_ldap_attributes() - - # Migrate old settings - migrate_legacy_permission_settings() - - except Exception: - logger.warn(m18n.n("migration_0019_migration_failed_trying_to_rollback")) - os.system("systemctl stop slapd") - os.system( - "rm -r /etc/ldap/slapd.d" - ) # To be sure that we don't keep some part of the old config - os.system("cp -r --preserve %s/ldap_config/. /etc/ldap/" % backup_folder) - os.system("cp -r --preserve %s/ldap_db/. /var/lib/ldap/" % backup_folder) - os.system( - "cp -r --preserve %s/apps_settings/. /etc/yunohost/apps/" - % backup_folder - ) - os.system("systemctl start slapd") - os.system("rm -r " + backup_folder) - logger.info(m18n.n("migration_0019_rollback_success")) - raise - else: - os.system("rm -r " + backup_folder) + # Migrate old settings + migrate_legacy_permission_settings() diff --git a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py index cd4f4c765..9796ca10d 100644 --- a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py @@ -19,9 +19,8 @@ class MyMigration(Migration): Add new permissions around SSH/SFTP features """ - required = True - - def run(self): + @ldap_migration + def run(self, *args): logger.info(m18n.n("migration_0020_ssh_sftp_permissions")) from yunohost.utils.ldap import _get_ldap_interface diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index e5699dede..a33460c39 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -1101,6 +1101,7 @@ def _skip_all_migrations(): write_to_yaml(MIGRATIONS_STATE_PATH, new_states) + class Migration(object): # Those are to be implemented by daughter classes @@ -1125,3 +1126,42 @@ class Migration(object): @property def description(self): return m18n.n("migration_description_%s" % self.id) + + def ldap_migration(run): + + def func(self): + + # Backup LDAP before the migration + logger.info(m18n.n("migration_ldap_backup_before_migration")) + try: + backup_folder = "/home/yunohost.backup/premigration/" + time.strftime( + "%Y%m%d-%H%M%S", time.gmtime() + ) + os.makedirs(backup_folder, 0o750) + os.system("systemctl stop slapd") + os.system(f"cp -r --preserve /etc/ldap {backup_folder}/ldap_config") + os.system(f"cp -r --preserve /var/lib/ldap {backup_folder}/ldap_db") + os.system(f"cp -r --preserve /etc/yunohost/apps {backup_folder}/apps_settings") + except Exception as e: + raise YunohostError( + "migration_ldap_can_not_backup_before_migration", error=e + ) + finally: + os.system("systemctl start slapd") + + try: + run(self, backup_folder) + except Exception: + logger.warn(m18n.n("migration_ldap_migration_failed_trying_to_rollback")) + os.system("systemctl stop slapd") + # To be sure that we don't keep some part of the old config + os.system("rm -r /etc/ldap/slapd.d") + os.system(f"cp -r --preserve {backup_folder}/ldap_config/. /etc/ldap/") + os.system(f"cp -r --preserve {backup_folder}/ldap_db/. /var/lib/ldap/") + os.system(f"cp -r --preserve {backup_folder}/apps_settings/. /etc/yunohost/apps/") + os.system("systemctl start slapd") + os.system(f"rm -r {backup_folder}") + logger.info(m18n.n("migration_ldap_rollback_success")) + raise + else: + os.system(f"rm -r {backup_folder}") From 83d03dc07446c0051a9404da6b487d6c0213e40d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Apr 2021 19:37:39 +0200 Subject: [PATCH 19/28] Simplify migration / be more explicit about what new rdn to inject --- locales/en.json | 1 - .../0020_ssh_sftp_permissions.py | 21 ++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/locales/en.json b/locales/en.json index 4c731863d..20a0c7703 100644 --- a/locales/en.json +++ b/locales/en.json @@ -451,7 +451,6 @@ "migration_0018_failed_to_reset_legacy_rules": "Failed to reset legacy iptables rules: {error}", "migration_0019_add_new_attributes_in_ldap": "Add new attributes for permissions in LDAP database", "migration_0019_slapd_config_will_be_overwritten": "It looks like you manually edited the slapd configuration. For this critical migration, YunoHost needs to force the update of the slapd configuration. The original files will be backuped in {conf_backup_folder}.", - "migration_0020_ssh_sftp_permissions": "SSH/SFTP permissions", "migrations_already_ran": "Those migrations are already done: {ids}", "migrations_cant_reach_migration_file": "Could not access migrations files at the path '%s'", "migrations_dependencies_not_satisfied": "Run these migrations: '{dependencies_id}', before migration {id}.", diff --git a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py index 9796ca10d..18c00d25e 100644 --- a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py @@ -19,25 +19,19 @@ class MyMigration(Migration): Add new permissions around SSH/SFTP features """ + dependencies = ["extend_permissions_features"] + @ldap_migration def run(self, *args): - logger.info(m18n.n("migration_0020_ssh_sftp_permissions")) from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() - add_perm_to_users = False - # Add SSH and SFTP permissions ldap_map = read_yaml('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml') - for rdn, attr_dict in ldap_map['depends_children'].items(): - try: - ldap.search(rdn + ",dc=yunohost,dc=org") - # ldap search will raise an exception if no corresponding object is found >.> ... - except Exception: - if rdn == "cn=ssh.main,ou=permission": - add_perm_to_users = True - ldap.add(rdn, attr_dict) + + ldap.add("cn=ssh.main,ou=permission", ldap_map['depends_children']["cn=ssh.main,ou=permission"]) + ldap.add("cn=sftp.main,ou=permission", ldap_map['depends_children']["cn=sftp.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"]) @@ -45,9 +39,12 @@ class MyMigration(Migration): if user['loginShell'][0] == '/bin/false': dn=user['dn'][0].replace(',dc=yunohost,dc=org', '') ldap.update(dn, {'loginShell': ['/bin/bash']}) - elif add_perm_to_users: + 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']) From 22e397f71c248d73a913d867cc04c0ef54409190 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Apr 2021 20:12:17 +0200 Subject: [PATCH 20/28] Fix oopsies --- .../0019_extend_permissions_features.py | 18 +++++++++--------- .../0020_ssh_sftp_permissions.py | 4 ++-- src/yunohost/tools.py | 5 ++++- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/yunohost/data_migrations/0019_extend_permissions_features.py b/src/yunohost/data_migrations/0019_extend_permissions_features.py index 30ae01ae4..d5e852701 100644 --- a/src/yunohost/data_migrations/0019_extend_permissions_features.py +++ b/src/yunohost/data_migrations/0019_extend_permissions_features.py @@ -17,6 +17,15 @@ class MyMigration(Migration): Add protected attribute in LDAP permission """ + @Migration.ldap_migration + def run(self, backup_folder): + + # Update LDAP database + self.add_new_ldap_attributes() + + # Migrate old settings + migrate_legacy_permission_settings() + def add_new_ldap_attributes(self): from yunohost.utils.ldap import _get_ldap_interface @@ -75,12 +84,3 @@ class MyMigration(Migration): } ldap.update("cn=%s,ou=permission" % permission, update) - - @ldap_migration - def run(self, backup_folder): - - # Update LDAP database - self.add_new_ldap_attributes() - - # Migrate old settings - migrate_legacy_permission_settings() diff --git a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py index 18c00d25e..d3368e4a0 100644 --- a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py @@ -5,7 +5,7 @@ from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_yaml from yunohost.tools import Migration -from yunohost.permission import user_permission_update +from yunohost.permission import user_permission_update, permission_sync_to_user logger = getActionLogger('yunohost.migration') @@ -21,7 +21,7 @@ class MyMigration(Migration): dependencies = ["extend_permissions_features"] - @ldap_migration + @Migration.ldap_migration def run(self, *args): from yunohost.utils.ldap import _get_ldap_interface diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index a33460c39..92c5982fd 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -28,6 +28,7 @@ import os import yaml import subprocess import pwd +import time from importlib import import_module from moulinette import msignals, m18n @@ -1144,7 +1145,7 @@ class Migration(object): os.system(f"cp -r --preserve /etc/yunohost/apps {backup_folder}/apps_settings") except Exception as e: raise YunohostError( - "migration_ldap_can_not_backup_before_migration", error=e + "migration_ldap_can_not_backup_before_migration", error=str(e) ) finally: os.system("systemctl start slapd") @@ -1165,3 +1166,5 @@ class Migration(object): raise else: os.system(f"rm -r {backup_folder}") + + return func From 5c2329c5b67a4b387315c078e9b360660ad96bf4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 1 Apr 2021 20:12:31 +0200 Subject: [PATCH 21/28] Refuse to add ssh/sftp permissions to all users --- locales/en.json | 1 + src/yunohost/permission.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/locales/en.json b/locales/en.json index 20a0c7703..0d80565a7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -498,6 +498,7 @@ "permission_created": "Permission '{permission:s}' created", "permission_creation_failed": "Could not create permission '{permission}': {error}", "permission_currently_allowed_for_all_users": "This permission is currently granted to all users in addition to other groups. You probably want to either remove the 'all_users' permission or remove the other groups it is currently granted to.", + "permission_cant_add_to_all_users": "The permission {permission} can not be added to all users.", "permission_deleted": "Permission '{permission:s}' deleted", "permission_deletion_failed": "Could not delete permission '{permission}': {error}", "permission_not_found": "Permission '{permission:s}' not found", diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index e0a3c6be8..df30b40c4 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -184,6 +184,10 @@ def user_permission_update( ) and not force: raise YunohostValidationError("permission_protected", permission=permission) + # Refuse to add "all_users" to ssh/sftp permissions + if permission.split(".")[0] in ["ssh", "sftp"] and (add and "all_users" in add) and not force: + raise YunohostValidationError("permission_cant_add_to_all_users", permission=permission) + # Fetch currently allowed groups for this permission current_allowed_groups = existing_permission["allowed"] From 4a0b343e5e7c2a8c4557ddbba51c93d93be27774 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 16 Apr 2021 22:01:22 +0200 Subject: [PATCH 22/28] Fix/update migration script, handle applying the new migration during restore --- .../0019_extend_permissions_features.py | 55 +------------------ .../0020_ssh_sftp_permissions.py | 11 +++- 2 files changed, 10 insertions(+), 56 deletions(-) diff --git a/src/yunohost/data_migrations/0019_extend_permissions_features.py b/src/yunohost/data_migrations/0019_extend_permissions_features.py index 3511cbb0b..240894202 100644 --- a/src/yunohost/data_migrations/0019_extend_permissions_features.py +++ b/src/yunohost/data_migrations/0019_extend_permissions_features.py @@ -91,7 +91,7 @@ class MyMigration(Migration): # Update LDAP database self.add_new_ldap_attributes() - def run_before_system_restore(self, app_id): + def run_before_app_restore(self, app_id): from yunohost.app import app_setting from yunohost.utils.legacy import migrate_legacy_permission_settings @@ -109,56 +109,3 @@ class MyMigration(Migration): for setting in legacy_permission_settings ): migrate_legacy_permission_settings(app=app_id) - - - def run(self): - - # FIXME : what do we really want to do here ... - # Imho we should just force-regen the conf in all case, and maybe - # just display a warning if we detect that the conf was manually modified - - # Backup LDAP and the apps settings before to do the migration - logger.info(m18n.n("migration_0019_backup_before_migration")) - try: - backup_folder = "/home/yunohost.backup/premigration/" + time.strftime( - "%Y%m%d-%H%M%S", time.gmtime() - ) - os.makedirs(backup_folder, 0o750) - os.system("systemctl stop slapd") - os.system("cp -r --preserve /etc/ldap %s/ldap_config" % backup_folder) - os.system("cp -r --preserve /var/lib/ldap %s/ldap_db" % backup_folder) - os.system( - "cp -r --preserve /etc/yunohost/apps %s/apps_settings" % backup_folder - ) - except Exception as e: - raise YunohostError( - "migration_0019_can_not_backup_before_migration", error=e - ) - finally: - os.system("systemctl start slapd") - - try: - # Update LDAP database - self.add_new_ldap_attributes() - - # Migrate old settings - migrate_legacy_permission_settings() - - except Exception: - logger.warn(m18n.n("migration_0019_migration_failed_trying_to_rollback")) - os.system("systemctl stop slapd") - os.system( - "rm -r /etc/ldap/slapd.d" - ) # To be sure that we don't keep some part of the old config - os.system("cp -r --preserve %s/ldap_config/. /etc/ldap/" % backup_folder) - os.system("cp -r --preserve %s/ldap_db/. /var/lib/ldap/" % backup_folder) - os.system( - "cp -r --preserve %s/apps_settings/. /etc/yunohost/apps/" - % backup_folder - ) - os.system("systemctl start slapd") - os.system("rm -r " + backup_folder) - logger.info(m18n.n("migration_0019_rollback_success")) - raise - else: - os.system("rm -r " + backup_folder) \ No newline at end of file diff --git a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py index d3368e4a0..97d4ee2fd 100644 --- a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py @@ -19,6 +19,7 @@ class MyMigration(Migration): Add new permissions around SSH/SFTP features """ + introduced_in_version = "4.2.2" dependencies = ["extend_permissions_features"] @Migration.ldap_migration @@ -37,14 +38,20 @@ class MyMigration(Migration): 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', '') + 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']) + + def run_after_system_restore(self): + self.run() + + def run_before_app_restore(self, app_id): + # Nothing to do during app backup restore for this migration + pass From c53f5ac16ae98e63105b2bb7790b1572124d23f5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 16 Apr 2021 22:05:36 +0200 Subject: [PATCH 23/28] Report an error in the diagnosis and migration if sshd config is insecure --- data/hooks/diagnosis/70-regenconf.py | 10 ++++++++++ locales/en.json | 1 + .../data_migrations/0020_ssh_sftp_permissions.py | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/data/hooks/diagnosis/70-regenconf.py b/data/hooks/diagnosis/70-regenconf.py index 5ab1e3808..b8551f5fe 100644 --- a/data/hooks/diagnosis/70-regenconf.py +++ b/data/hooks/diagnosis/70-regenconf.py @@ -35,6 +35,16 @@ class RegenconfDiagnoser(Diagnoser): details=["diagnosis_regenconf_manually_modified_details"], ) + if any(f["path"] == '/etc/ssh/sshd_config' for f in regenconf_modified_files) \ + and os.system("grep -q '^ *AllowGroups\\|^ *AllowUsers' /etc/ssh/sshd_config") != 0: + yield dict( + meta={ + "test": "sshd_config_insecure" + }, + status="ERROR", + summary="diagnosis_sshd_config_insecure", + ) + def manually_modified_files(self): for category, infos in _get_regenconf_infos().items(): diff --git a/locales/en.json b/locales/en.json index 027fe981e..840d359ed 100644 --- a/locales/en.json +++ b/locales/en.json @@ -269,6 +269,7 @@ "diagnosis_unknown_categories": "The following categories are unknown: {categories}", "diagnosis_never_ran_yet": "It looks like this server was setup recently and there's no diagnosis report to show yet. You should start by running a full diagnosis, either from the webadmin or using 'yunohost diagnosis run' from the command line.", "diagnosis_processes_killed_by_oom_reaper": "Some processes were recently killed by the system because it ran out of memory. This is typically symptomatic of a lack of memory on the system or of a process that ate up to much memory. Summary of the processes killed:\n{kills_summary}", + "diagnosis_sshd_config_insecure": "The SSH configuration appears to have been manually modified, and is insecure because it contains no 'AllowGroups' or 'AllowUsers' directive to limit access to authorized users.", "domain_cannot_remove_main": "You cannot remove '{domain:s}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n '; here is the list of candidate domains: {other_domains:s}", "domain_cannot_add_xmpp_upload": "You cannot add domains starting with 'xmpp-upload.'. This kind of name is reserved for the XMPP upload feature integrated in YunoHost.", "domain_cannot_remove_main_add_new_one": "You cannot remove '{domain:s}' since it's the main domain and your only domain, you need to first add another domain using 'yunohost domain add ', then set is as the main domain using 'yunohost domain main-domain -n ' and then you can remove the domain '{domain:s}' using 'yunohost domain remove {domain:s}'.'", diff --git a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py index 97d4ee2fd..52d813d32 100644 --- a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py @@ -1,4 +1,5 @@ import subprocess +import os from moulinette import m18n from moulinette.utils.log import getActionLogger @@ -6,6 +7,7 @@ from moulinette.utils.filesystem import read_yaml from yunohost.tools import Migration from yunohost.permission import user_permission_update, permission_sync_to_user +from yunohost.regenconf import manually_modified_files logger = getActionLogger('yunohost.migration') @@ -49,6 +51,10 @@ class MyMigration(Migration): # 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 run_after_system_restore(self): self.run() From 8f3a7067d9a024444edfe76b7414f5fa5c264a4a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 16 Apr 2021 22:20:06 +0200 Subject: [PATCH 24/28] Advertise the new SSH port setting for people that manually modified the SSH port --- data/hooks/diagnosis/70-regenconf.py | 19 ++++++++++++++++++- locales/en.json | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/70-regenconf.py b/data/hooks/diagnosis/70-regenconf.py index b8551f5fe..4e40c71fb 100644 --- a/data/hooks/diagnosis/70-regenconf.py +++ b/data/hooks/diagnosis/70-regenconf.py @@ -1,10 +1,12 @@ #!/usr/bin/env python import os +import re +from yunohost.settings import settings_get from yunohost.diagnosis import Diagnoser from yunohost.regenconf import _get_regenconf_infos, _calculate_hash - +from moulinette.utils.filesystem import read_file class RegenconfDiagnoser(Diagnoser): @@ -45,6 +47,21 @@ class RegenconfDiagnoser(Diagnoser): summary="diagnosis_sshd_config_insecure", ) + # Check consistency between actual ssh port in sshd_config vs. setting + ssh_port_setting = settings_get('security.ssh.port') + ssh_port_line = re.findall( + r"\bPort *([0-9]{2,5})\b", read_file("/etc/ssh/sshd_config") + ) + if len(ssh_port_line) == 1 and int(ssh_port_line[0]) != ssh_port_setting: + yield dict( + meta={ + "test": "sshd_config_port_inconsistency" + }, + status="WARNING", + summary="diagnosis_sshd_config_inconsistent", + details=["diagnosis_sshd_config_inconsistent_details"], + ) + def manually_modified_files(self): for category, infos in _get_regenconf_infos().items(): diff --git a/locales/en.json b/locales/en.json index 840d359ed..63d5c6b10 100644 --- a/locales/en.json +++ b/locales/en.json @@ -270,6 +270,8 @@ "diagnosis_never_ran_yet": "It looks like this server was setup recently and there's no diagnosis report to show yet. You should start by running a full diagnosis, either from the webadmin or using 'yunohost diagnosis run' from the command line.", "diagnosis_processes_killed_by_oom_reaper": "Some processes were recently killed by the system because it ran out of memory. This is typically symptomatic of a lack of memory on the system or of a process that ate up to much memory. Summary of the processes killed:\n{kills_summary}", "diagnosis_sshd_config_insecure": "The SSH configuration appears to have been manually modified, and is insecure because it contains no 'AllowGroups' or 'AllowUsers' directive to limit access to authorized users.", + "diagnosis_sshd_config_inconsistent": "It looks like the SSH port was manually modified in /etc/ssh/sshd_config. Since Yunohost 4.2, a new global setting 'security.ssh.port' is available to avoid manually editing the configuration.", + "diagnosis_sshd_config_inconsistent_details": "Please run yunohost settings set security.ssh.port -v YOUR_SSH_PORT to define the SSH port, and check yunohost tools regen-conf ssh --dry-run --with-diff and yunohost tools regen-conf ssh --force to reset your conf to the Yunohost recommendation.", "domain_cannot_remove_main": "You cannot remove '{domain:s}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n '; here is the list of candidate domains: {other_domains:s}", "domain_cannot_add_xmpp_upload": "You cannot add domains starting with 'xmpp-upload.'. This kind of name is reserved for the XMPP upload feature integrated in YunoHost.", "domain_cannot_remove_main_add_new_one": "You cannot remove '{domain:s}' since it's the main domain and your only domain, you need to first add another domain using 'yunohost domain add ', then set is as the main domain using 'yunohost domain main-domain -n ' and then you can remove the domain '{domain:s}' using 'yunohost domain remove {domain:s}'.'", From aae7c6e2966abb43702cb65dffb15c9aa888fd4e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 16 Apr 2021 22:34:39 +0200 Subject: [PATCH 25/28] Unused imports --- .../data_migrations/0019_extend_permissions_features.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/yunohost/data_migrations/0019_extend_permissions_features.py b/src/yunohost/data_migrations/0019_extend_permissions_features.py index 240894202..5d4343deb 100644 --- a/src/yunohost/data_migrations/0019_extend_permissions_features.py +++ b/src/yunohost/data_migrations/0019_extend_permissions_features.py @@ -1,8 +1,4 @@ -import time -import os - from moulinette import m18n -from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger from yunohost.tools import Migration From 72e4a584ed19eb9f2bb195a589625f83c90e2741 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 17 Apr 2021 00:58:12 +0200 Subject: [PATCH 26/28] Be more robust against re-running the migration --- .../0020_ssh_sftp_permissions.py | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py index 52d813d32..c3b7a91ec 100644 --- a/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py +++ b/src/yunohost/data_migrations/0020_ssh_sftp_permissions.py @@ -30,26 +30,32 @@ class MyMigration(Migration): 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') - ldap.add("cn=ssh.main,ou=permission", ldap_map['depends_children']["cn=ssh.main,ou=permission"]) - ldap.add("cn=sftp.main,ou=permission", ldap_map['depends_children']["cn=sftp.main,ou=permission"]) + if "sftp.main" not in existing_perms: + ldap.add("cn=sftp.main,ou=permission", ldap_map['depends_children']["cn=sftp.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) + if "ssh.main" not in existing_perms: + ldap.add("cn=ssh.main,ou=permission", ldap_map['depends_children']["cn=ssh.main,ou=permission"]) - permission_sync_to_user() + # 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) - # Somehow this is needed otherwise the PAM thing doesn't forget about the - # old loginShell value ? - subprocess.call(['nscd', '-i', 'passwd']) + 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: From 3b35f6102829db24eee9d6f7608b304a5a026729 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 17 Apr 2021 01:00:28 +0200 Subject: [PATCH 27/28] Fix DepreciationWarning --- src/yunohost/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 29456f959..a7eb6281d 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -1205,7 +1205,7 @@ class Migration(object): try: run(self, backup_folder) except Exception: - logger.warn(m18n.n("migration_ldap_migration_failed_trying_to_rollback")) + logger.warning(m18n.n("migration_ldap_migration_failed_trying_to_rollback")) os.system("systemctl stop slapd") # To be sure that we don't keep some part of the old config os.system("rm -r /etc/ldap/slapd.d") From 16e20fed7774e1130ee5a291400fa00656fd9be1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 17 Apr 2021 01:10:58 +0200 Subject: [PATCH 28/28] Don't re-run migration if backup is from the same version (mainly to avoid weird stuff during tests) --- src/yunohost/tools.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index a7eb6281d..8fb65bac8 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -1122,9 +1122,15 @@ def _tools_migrations_run_after_system_restore(backup_version): all_migrations = _get_migrations_list() + current_version = version.parse(ynh_packages_version()["yunohost"]["version"]) + backup_version = version.parse(backup_version) + + if backup_version == current_version: + return + for migration in all_migrations: if hasattr(migration, "introduced_in_version") \ - and version.parse(migration.introduced_in_version) > version.parse(backup_version) \ + and version.parse(migration.introduced_in_version) > backup_version \ and hasattr(migration, "run_after_system_restore"): try: logger.info(m18n.n("migrations_running_forward", id=migration.id)) @@ -1141,9 +1147,15 @@ def _tools_migrations_run_before_app_restore(backup_version, app_id): all_migrations = _get_migrations_list() + current_version = version.parse(ynh_packages_version()["yunohost"]["version"]) + backup_version = version.parse(backup_version) + + if backup_version == current_version: + return + for migration in all_migrations: if hasattr(migration, "introduced_in_version") \ - and version.parse(migration.introduced_in_version) > version.parse(backup_version) \ + and version.parse(migration.introduced_in_version) > backup_version \ and hasattr(migration, "run_before_app_restore"): try: logger.info(m18n.n("migrations_running_forward", id=migration.id))