diff --git a/gunicorn/config.py b/gunicorn/config.py index af63407c..0558530c 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -987,6 +987,23 @@ class Umask(Setting): """ +class Initgroups(Setting): + name = "initgroups" + section = "Server Mechanics" + cli = ["--initgroups"] + validator = validate_bool + action = 'store_true' + default = False + + desc = """\ + If true, set the worker process's group access list with all of the + groups of which the specified username is a member, plus the specified + group id. + + .. versionadded:: 19.7 + """ + + class TmpUploadDir(Setting): name = "tmp_upload_dir" section = "Server Mechanics" diff --git a/gunicorn/util.py b/gunicorn/util.py index 64c5ff57..a011fb85 100644 --- a/gunicorn/util.py +++ b/gunicorn/util.py @@ -54,6 +54,7 @@ hop_headers = set(""" try: from setproctitle import setproctitle + def _setproctitle(title): setproctitle("gunicorn: %s" % title) except ImportError: @@ -147,13 +148,30 @@ def load_class(uri, default="gunicorn.workers.sync.SyncWorker", return getattr(mod, klass) -def set_owner_process(uid, gid): +def get_username(uid): + """ get the username for a user id""" + return pwd.getpwuid(uid).pw_name + + +def set_owner_process(uid, gid, initgroups=False): """ set user and group of workers processes """ + if gid: + if uid: + try: + username = get_username(uid) + except KeyError: + initgroups = False + # versions of python < 2.6.2 don't manage unsigned int for # groups like on osx or fedora gid = abs(gid) & 0x7FFFFFFF - os.setgid(gid) + + if initgroups: + os.initgroups(username, gid) + else: + os.setgid(gid) + if uid: os.setuid(uid) diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py index c00101df..4ceb691b 100644 --- a/gunicorn/workers/base.py +++ b/gunicorn/workers/base.py @@ -102,7 +102,8 @@ class Worker(object): for k, v in self.cfg.env.items(): os.environ[k] = v - util.set_owner_process(self.cfg.uid, self.cfg.gid) + util.set_owner_process(self.cfg.uid, self.cfg.gid, + initgroups=self.cfg.initgroups) # Reseed the random number generator util.seed()