From 41991590ca0e214c79da80130583c6aaaf77388c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Mon, 25 Jan 2021 14:58:50 +0100 Subject: [PATCH] added support for running as root and drop to an user later --- tunnel-server/src/uds_tunnel/config.py | 2 ++ tunnel-server/src/udstunnel.conf | 1 + tunnel-server/src/udstunnel.py | 45 ++++++++++++++++---------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/tunnel-server/src/uds_tunnel/config.py b/tunnel-server/src/uds_tunnel/config.py index 0f213805a..d096a58d5 100644 --- a/tunnel-server/src/uds_tunnel/config.py +++ b/tunnel-server/src/uds_tunnel/config.py @@ -40,6 +40,7 @@ logger = logging.getLogger(__name__) class ConfigurationType(typing.NamedTuple): pidfile: str + user: str log_level: str log_file: str @@ -90,6 +91,7 @@ def read() -> ConfigurationType: logsize = logsize[:-1] return ConfigurationType( pidfile=uds.get('pidfile', ''), + user=uds.get('user', ''), log_level=uds.get('loglevel', 'ERROR'), log_file=uds.get('logfile', ''), log_size=int(logsize)*1024*1024, diff --git a/tunnel-server/src/udstunnel.conf b/tunnel-server/src/udstunnel.conf index ff5c71fde..4cb2d9b43 100644 --- a/tunnel-server/src/udstunnel.conf +++ b/tunnel-server/src/udstunnel.conf @@ -2,6 +2,7 @@ # Pid file, optional # pidfile = /tmp/udstunnel.pid +user = dkmaster # Log level, valid are DEBUG, INFO, WARN, ERROR. Defaults to ERROR loglevel = DEBUG diff --git a/tunnel-server/src/udstunnel.py b/tunnel-server/src/udstunnel.py index cff2f6e0b..7aade379b 100755 --- a/tunnel-server/src/udstunnel.py +++ b/tunnel-server/src/udstunnel.py @@ -30,6 +30,7 @@ @author: Adolfo Gómez, dkmaster at dkmon dot com ''' import os +import pwd import sys import argparse import multiprocessing @@ -154,16 +155,42 @@ async def tunnel_proc_async( def tunnel_main(): cfg = config.read() - # Create pid file + # Try to bind to port as running user + # Wait for socket incoming connections and spread them + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + sock.settimeout(3.0) # So we can check for stop from time to time + # We will not reuse port, we only want a UDS tunnel server running on a port + # but this may change on future... + # try: + # sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True) + # except (AttributeError, OSError) as e: + # logger.warning('socket.REUSEPORT not available') try: + sock.bind((cfg.listen_address, cfg.listen_port)) + sock.listen(BACKLOG) + + # If running as root, and requested drop privileges after port bind + if os.getuid() == 0 and cfg.user: + logger.debug('Changing to user %s', cfg.user) + pwu = pwd.getpwnam(cfg.user) + os.setgid(pwu.pw_gid) + os.setuid(pwu.pw_uid) + setup_log(cfg) + + # Create pid file if cfg.pidfile: with open(cfg.pidfile, mode='w') as f: f.write(str(os.getpid())) + except Exception as e: sys.stderr.write(f'Tunnel startup error: {e}\n') + logger.error('MAIN: %s', e) return + # Setup signal handlers signal.signal(signal.SIGINT, stop_signal) signal.signal(signal.SIGTERM, stop_signal) @@ -194,23 +221,7 @@ def tunnel_main(): best = (percent, c[0]) return best[1] - sock = None try: - # Wait for socket incoming connections and spread them - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - - # We will not reuse port, we only want a UDS tunnel server running on a port - # but this may change on future... - # try: - # sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True) - # except (AttributeError, OSError) as e: - # logger.warning('socket.REUSEPORT not available') - - sock.settimeout(3.0) # So we can check for stop from time to time - sock.bind((cfg.listen_address, cfg.listen_port)) - sock.listen(BACKLOG) while not do_stop: try: client, addr = sock.accept()