diff --git a/pyzenkit/baseapp.py b/pyzenkit/baseapp.py index 0acacfcff9f6257a7841f6ca16cb7e9eb25e31c7..9f54c4f7ca09a9a51e6c317964f215aefdcad2cf 100644 --- a/pyzenkit/baseapp.py +++ b/pyzenkit/baseapp.py @@ -24,6 +24,8 @@ usefull features including (but not limited to) following: import os import sys +import pwd +import grp import re import shutil import glob @@ -148,6 +150,8 @@ class BaseApp: CONFIG_ACTION = 'action' CONFIG_INPUT = 'input' CONFIG_LIMIT = 'limit' + CONFIG_USER = 'user' + CONFIG_GROUP = 'group' CONFIG_CFG_FILE = 'config_file' CONFIG_CFG_DIR = 'config_dir' CONFIG_LOG_FILE = 'log_file' @@ -269,6 +273,12 @@ class BaseApp: # Option for setting the result limit. argparser.add_argument('--limit', help = 'apply given limit to the result', type = int) + # Option for overriding the process UID. + argparser.add_argument('--user', help = 'process UID or user name') + + # Option for overriding the process GID. + argparser.add_argument('--group', help = 'process GID or group name') + # Option for overriding the name of the configuration file. argparser.add_argument('--config-file', help = 'name of the config file') @@ -376,6 +386,8 @@ class BaseApp: (self.CONFIG_ACTION, None), (self.CONFIG_INPUT, None), (self.CONFIG_LIMIT, None), + (self.CONFIG_USER, None), + (self.CONFIG_GROUP, None), (self.CONFIG_CFG_FILE, os.path.join(self.paths.get(self.PATH_CFG), "{}.conf".format(self.name))), (self.CONFIG_CFG_DIR, os.path.join(self.paths.get(self.PATH_CFG), "{}".format(self.name))), (self.CONFIG_LOG_FILE, os.path.join(self.paths.get(self.PATH_LOG), "{}.log".format(self.name))), @@ -602,6 +614,42 @@ class BaseApp: cc[self.CORE_RUNLOG_SAVE] = True self.config[self.CORE][self.CORE_RUNLOG] = cc + if self.config[self.CONFIG_USER]: + u = self.config[self.CONFIG_USER] + res = None + if not res: + try: + res = pwd.getpwnam(u) + self.config[self.CONFIG_USER] = [res[0], res[2]] + except: + pass + if not res: + try: + res = pwd.getpwuid(int(u)) + self.config[self.CONFIG_USER] = [res[0], res[2]] + except: + pass + if not res: + raise ZenAppSetupException("Unknown user account '{}'".format(u)) + + if self.config[self.CONFIG_GROUP]: + g = self.config[self.CONFIG_GROUP] + res = None + if not res: + try: + res = grp.getgrnam(g) + self.config[self.CONFIG_GROUP] = [res[0], res[2]] + except: + pass + if not res: + try: + res = grp.getgrgid(int(g)) + self.config[self.CONFIG_GROUP] = [res[0], res[2]] + except: + pass + if not res: + raise ZenAppSetupException("Unknown group account '{}'".format(g)) + def _configure_check(self): """ TODO: Implement config checking mechanism. @@ -636,6 +684,21 @@ class BaseApp: # Check all loaded configurations. self._configure_check() + def _stage_setup_privileges(self): + """ + Adjust the script privileges according to the configration. + """ + g = self.c(self.CONFIG_GROUP, None) + if g and g[1] != os.getgid(): + cg = grp.getgrgid(os.getgid()) + self.dbgout("[STATUS] Dropping group privileges from '{}':'{}' to '{}':'{}'".format(cg[0], cg[2], g[0], g[1])) + os.setgid(g[1]) + u = self.c(self.CONFIG_USER, None) + if u and u[1] != os.getuid(): + cu = pwd.getpwuid(os.getuid()) + self.dbgout("[STATUS] Dropping user privileges from '{}':'{}' to '{}':'{}'".format(cu[0], cu[2], u[0], u[1])) + os.setuid(u[1]) + def _stage_setup_logging(self): """ Setup terminal and file logging facilities. @@ -757,6 +820,9 @@ class BaseApp: # Setup configurations. self._stage_setup_configuration() + # Setup script privileges + self._stage_setup_privileges() + # Setup logging, if the appropriate feature is enabled. if self.c(self.CONFIG_LOG_FILE): self._stage_setup_logging() diff --git a/pyzenkit/zendaemon.py b/pyzenkit/zendaemon.py index 39a269a797586b401d41bf4c54d8b289375494eb..4b9cc8cd8a4f26c5dcc47d1ae6013fddb41f0498 100644 --- a/pyzenkit/zendaemon.py +++ b/pyzenkit/zendaemon.py @@ -12,8 +12,6 @@ Base implementation of generic daemon. import os import re import sys -import pwd -import grp import json import time import copy @@ -252,8 +250,6 @@ class ZenDaemon(pyzenkit.baseapp.BaseApp): CONFIG_PID_FILE = 'pid_file' CONFIG_STATE_FILE = 'state_file' CONFIG_UMASK = 'umask' - CONFIG_USER = 'user' - CONFIG_GROUP = 'group' CONFIG_STATS_INTERVAL = 'stats_interval' CONFIG_PARALEL = 'paralel' @@ -284,8 +280,6 @@ class ZenDaemon(pyzenkit.baseapp.BaseApp): (self.CONFIG_PID_FILE, os.path.join(self.paths.get(self.PATH_RUN), "{}.pid".format(self.name))), (self.CONFIG_STATE_FILE, os.path.join(self.paths.get(self.PATH_RUN), "{}.state".format(self.name))), (self.CONFIG_UMASK, None), - (self.CONFIG_USER, None), - (self.CONFIG_GROUP, None), (self.CONFIG_STATS_INTERVAL, 300), (self.CONFIG_PARALEL, False), ) @@ -318,12 +312,6 @@ class ZenDaemon(pyzenkit.baseapp.BaseApp): # Option for overriding the default umask. argparser.add_argument('--umask', help = 'default file umask') - # Option for overriding the process UID. - argparser.add_argument('--user', help = 'process UID or user name') - - # Option for overriding the process GID. - argparser.add_argument('--group', help = 'process GID or group name') - # Option for defining processing statistics display interval. argparser.add_argument('--stats-interval', help = 'define processing statistics display interval') @@ -400,43 +388,6 @@ class ZenDaemon(pyzenkit.baseapp.BaseApp): self.config[self.CORE][self.CORE_RUNLOG][self.CORE_RUNLOG_SAVE] = True self.config[self.CORE][self.CORE_PSTATE][self.CORE_PSTATE_SAVE] = True - if self.config[self.CONFIG_USER]: - u = self.config[self.CONFIG_USER] - res = None - if not res: - try: - res = pwd.getpwnam(u) - self.config[self.CONFIG_USER] = res[2] - except: - pass - if not res: - try: - res = pwd.getpwuid(int(u)) - self.config[self.CONFIG_USER] = res[2] - except: - pass - if not res: - raise ZenDaemonException("Unknown user '{}'".format(u)) - - if self.config[self.CONFIG_GROUP]: - g = self.config[self.CONFIG_GROUP] - res = None - if not res: - try: - res = grp.getgrnam(g) - self.config[self.CONFIG_GROUP] = res[2] - except: - pass - if not res: - try: - res = grp.getgruid(int(g)) - self.config[self.CONFIG_GROUP] = res[2] - except: - pass - if not res: - raise ZenDaemonException("Unknown group '{}'".format(g)) - - def _stage_setup_custom(self): """ Perform custom daemon related setup. @@ -742,8 +693,6 @@ class ZenDaemon(pyzenkit.baseapp.BaseApp): work_dir = self.c(self.CONFIG_WORK_DIR), pidfile = self.get_fn_pidfile(), umask = self.c(self.CONFIG_UMASK), - uid = self.c(self.CONFIG_USER), - gid = self.c(self.CONFIG_GROUP), files_preserve = logs, signals = { signal.SIGHUP: self._hnd_signal_hup, @@ -765,8 +714,6 @@ class ZenDaemon(pyzenkit.baseapp.BaseApp): work_dir = self.c(self.CONFIG_WORK_DIR), pidfile = self.get_fn_pidfile(), umask = self.c(self.CONFIG_UMASK), - uid = self.c(self.CONFIG_USER), - gid = self.c(self.CONFIG_GROUP), signals = { signal.SIGHUP: self._hnd_signal_hup, signal.SIGUSR1: self._hnd_signal_usr1, diff --git a/setup.py b/setup.py index c4ac641f963341cc3db23daf16581a61c4b1f916..0a4a8e368bf17649d3b956295c77bd52f27b268e 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ with open(path.join(here, 'README.rst'), encoding='utf-8') as f: setup( name = 'pyzenkit', - version = '0.13', + version = '0.16', description = 'Python 3 script and daemon toolkit', long_description = long_description, classifiers = [