From 7b9b4bacc9efa579fcc9ca34a455b3cf6d22d2e5 Mon Sep 17 00:00:00 2001 From: Philip ABBET <philip.abbet@idiap.ch> Date: Wed, 13 Sep 2017 14:31:35 +0200 Subject: [PATCH] Change the way UIDs are handled --- beat/backend/python/helpers.py | 1 + beat/backend/python/scripts/execute.py | 94 ++++++++++++++++++-------- 2 files changed, 67 insertions(+), 28 deletions(-) mode change 100644 => 100755 beat/backend/python/scripts/execute.py diff --git a/beat/backend/python/helpers.py b/beat/backend/python/helpers.py index afb2382..40229b2 100755 --- a/beat/backend/python/helpers.py +++ b/beat/backend/python/helpers.py @@ -44,6 +44,7 @@ def convert_experiment_configuration_to_container(config, proxy_mode): 'algorithm': config['algorithm'], 'parameters': config['parameters'], 'channel': config['channel'], + 'uid': os.getuid(), } if 'range' in config: diff --git a/beat/backend/python/scripts/execute.py b/beat/backend/python/scripts/execute.py old mode 100644 new mode 100755 index 91e7931..4a130ed --- a/beat/backend/python/scripts/execute.py +++ b/beat/backend/python/scripts/execute.py @@ -54,6 +54,8 @@ import sys import docopt import pwd import stat +import simplejson +import subprocess import zmq @@ -69,6 +71,9 @@ class UserError(Exception): return repr(self.value) +#---------------------------------------------------------- + + def send_error(logger, socket, tp, message): """Sends a user (usr) or system (sys) error message to the infrastructure""" @@ -98,6 +103,19 @@ def send_error(logger, socket, tp, message): logger.error('stopping 0MQ client anyway') +#---------------------------------------------------------- + + +def close(logger, socket, context): + socket.setsockopt(zmq.LINGER, 0) + socket.close() + context.term() + logger.debug("0MQ client finished") + + +#---------------------------------------------------------- + + def main(): """ @@ -113,6 +131,7 @@ def main(): args = docopt.docopt(__doc__ % dict(prog=prog, version=version), version=version) + # Sets up the logging system if args['--debug']: logging.basicConfig(format='[remote|%(name)s] %(levelname)s: %(message)s', @@ -123,27 +142,6 @@ def main(): logger = logging.getLogger(__name__) - # Attempt to change to an user with less privileges - try: - # First determine if the user exists. If not, none of the following lines will - # be executed - newuid = pwd.getpwnam('beat-nobody').pw_uid - - # Next, ensure that the needed files are readable by the 'beat-nobody' user - access = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH - - os.chmod(args['<dir>'], access) - - for root, dirs, files in os.walk(args['<dir>']): - for d in dirs: - os.chmod(os.path.join(root, d), access) - for f in files: - os.chmod(os.path.join(root, f), access) - - # Change the user - os.setuid(newuid) - except: - pass # Creates the 0MQ socket for communication with BEAT context = zmq.Context() @@ -152,12 +150,52 @@ def main(): socket.connect(address) logger.debug("zmq client connected to `%s'", address) + + # Check the dir + if not os.path.exists(args['<dir>']): + send_error(logger, socket, 'sys', "Running directory `%s' not found" % args['<dir>']) + close(logger, socket, context) + return 1 + + + # Create a new user with less privileges + with open(os.path.join(args['<dir>'], 'configuration.json'), 'r') as f: + cfg = simplejson.load(f) + + retcode = subprocess.call(['adduser', '--uid', str(cfg['uid']), + '--no-create-home', '--disabled-password', + '--disabled-login', '--gecos', '""', '-q', + 'beat-nobody']) + if retcode != 0: + send_error(logger, socket, 'sys', 'Failed to create an user with the UID %d' % cfg['uid']) + close(logger, socket, context) + return 1 + + + # Ensure that the needed files are readable by the new user + access = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH + + os.chmod(args['<dir>'], access) + + for root, dirs, files in os.walk(args['<dir>']): + for d in dirs: + os.chmod(os.path.join(root, d), access) + for f in files: + os.chmod(os.path.join(root, f), access) + + + # Change to the user with less privileges try: + os.setgid(cfg['uid']) + os.setuid(cfg['uid']) + except: + import traceback + send_error(logger, socket, 'sys', traceback.format_exc()) + close(logger, socket, context) + return 1 - # Check the dir - if not os.path.exists(args['<dir>']): - raise IOError("Running directory `%s' not found" % args['<dir>']) + try: # Sets up the execution executor = Executor(socket, args['<dir>']) @@ -210,13 +248,13 @@ def main(): return 1 finally: - socket.setsockopt(zmq.LINGER, 0) - socket.close() - context.term() - logger.debug("0MQ client finished") + close(logger, socket, context) return 0 +#---------------------------------------------------------- + + if __name__ == '__main__': sys.exit(main()) -- GitLab