From 6b61ca2f188b7b660c8e3bb243a70435862ed2f1 Mon Sep 17 00:00:00 2001 From: Veiko Aasa Date: Fri, 28 Aug 2020 11:47:04 +0300 Subject: [PATCH] ssh: action script: Require user credentials when editing ssh keys This change prevents the plinth user to set the ssh-keys without knowing the user password. - Debian: added new dependency python3-pampy to authenticate users. - Added additional required parameter --auth-user to the 'actions/ssh set-keys' command. A password should be provided through STDIN. Tests performed: - running 'actions/ssh set-keys' with empty or wrong admin credentials fails. - running 'actions/ssh set-keys' with correct admin credentials succeeds. - running 'actions/ssh set-keys' with correct non-admin credentials succeeds if the --username is the same user. - running 'actions/ssh set-keys' with correct non-admin credentials fails if the --username is a different user. Signed-off-by: Veiko Aasa Reviewed-by: Sunil Mohan Adapa --- actions/ssh | 31 ++++++++++++++++++++++++++++++- debian/control | 2 ++ plinth/utils.py | 7 +++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/actions/ssh b/actions/ssh index d2aee9319..cc777170d 100755 --- a/actions/ssh +++ b/actions/ssh @@ -5,6 +5,7 @@ Configuration helper for SSH server. """ import argparse +import grp import os import pwd import shutil @@ -14,7 +15,7 @@ import sys import augeas -from plinth import action_utils +from plinth import action_utils, utils def parse_arguments(): @@ -32,6 +33,7 @@ def parse_arguments(): help='Set SSH authorized keys') set_keys.add_argument('--username', required=True, type=_managed_user) set_keys.add_argument('--keys', required=True) + set_keys.add_argument('--auth-user', required=True) subparsers.add_parser('get-password-config', help='Get SSH password auth configuration') @@ -44,6 +46,24 @@ def parse_arguments(): return parser.parse_args() +def _validate_user(username, must_be_admin=True): + """Validate a user.""" + if must_be_admin: + try: + admins = grp.getgrnam('admin').gr_mem + except KeyError: + admins = [] + + if username not in admins: + msg = '"{}" is not authorized to perform this action'.format( + username) + raise argparse.ArgumentTypeError(msg) + + password = _read_password() + if not utils.is_authenticated_user(username, password): + raise argparse.ArgumentTypeError("Invalid credentials") + + def _managed_user(username): """Raise an error if the user is root.""" if pwd.getpwnam(username).pw_gid == 0: @@ -52,6 +72,11 @@ def _managed_user(username): return username +def _read_password(): + """Read the password from stdin.""" + return ''.join(sys.stdin) + + def subcommand_setup(arguments): """Setup Open SSH server. @@ -91,6 +116,10 @@ def subcommand_get_keys(arguments): def subcommand_set_keys(arguments): """Set SSH authorized keys.""" user = arguments.username + auth_user = arguments.auth_user + + must_be_admin = user != auth_user + _validate_user(auth_user, must_be_admin=must_be_admin) ssh_folder = os.path.join(get_user_homedir(user), '.ssh') key_file_path = os.path.join(ssh_folder, 'authorized_keys') diff --git a/debian/control b/debian/control index c3c10670d..f90820a40 100644 --- a/debian/control +++ b/debian/control @@ -32,6 +32,7 @@ Build-Depends: python3-flake8, python3-gi, python3-markupsafe, + python3-pampy, python3-paramiko, python3-psutil, python3-pytest, @@ -104,6 +105,7 @@ Depends: python3-django-stronghold, python3-gi, python3-markupsafe, + python3-pampy, python3-paramiko, python3-psutil, python3-requests, diff --git a/plinth/utils.py b/plinth/utils.py index 80ca0e336..a2dfcb6be 100644 --- a/plinth/utils.py +++ b/plinth/utils.py @@ -12,6 +12,7 @@ import string from distutils.version import LooseVersion import markupsafe +import pam import ruamel.yaml from django.utils.functional import lazy @@ -156,3 +157,9 @@ def is_axes_old(): return False return LooseVersion(version) < LooseVersion('5.0') + + +def is_authenticated_user(username, password): + """Return true if the user authentication succeeds.""" + pam_authenticator = pam.pam() + return bool(pam_authenticator.authenticate(username, password))