|
@@ -283,7 +283,9 @@ def detached(logfile=None, pidfile=None, uid=None, gid=None, umask=0,
|
|
workdir = os.getcwd() if workdir is None else workdir
|
|
workdir = os.getcwd() if workdir is None else workdir
|
|
|
|
|
|
signals.reset("SIGCLD") # Make sure SIGCLD is using the default handler.
|
|
signals.reset("SIGCLD") # Make sure SIGCLD is using the default handler.
|
|
- set_effective_user(uid=uid, gid=gid)
|
|
|
|
|
|
+ if not os.geteuid():
|
|
|
|
+ # no point trying to setuid unless we're root.
|
|
|
|
+ maybe_drop_privileges(uid=uid, gid=gid)
|
|
|
|
|
|
# Since without stderr any errors will be silently suppressed,
|
|
# Since without stderr any errors will be silently suppressed,
|
|
# we need to know that we have access to the logfile.
|
|
# we need to know that we have access to the logfile.
|
|
@@ -330,12 +332,49 @@ def parse_gid(gid):
|
|
raise
|
|
raise
|
|
|
|
|
|
|
|
|
|
-def setgroups(uid):
|
|
|
|
|
|
+def _setgroups_hack(groups):
|
|
|
|
+ """:fun:`setgroups` may have a platform-dependent limit,
|
|
|
|
+ and it is not always possible to know in advance what this limit
|
|
|
|
+ is, so we use this ugly hack stolen from glibc."""
|
|
|
|
+ groups = groups[:]
|
|
|
|
+
|
|
|
|
+ while 1:
|
|
|
|
+ try:
|
|
|
|
+ return os.setgroups(groups)
|
|
|
|
+ except ValueError: # error from Python's check.
|
|
|
|
+ if len(groups) <= 1:
|
|
|
|
+ raise
|
|
|
|
+ groups[:] = groups[:-1]
|
|
|
|
+ except OSError, exc: # error from the OS.
|
|
|
|
+ if exc.errno != errno.EINVAL or len(groups) <= 1:
|
|
|
|
+ raise
|
|
|
|
+ groups[:] = groups[:-1]
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def setgroups(groups):
|
|
|
|
+ max_groups = None
|
|
|
|
+ try:
|
|
|
|
+ max_groups = os.sysconf("SC_NGROUPS_MAX")
|
|
|
|
+ except:
|
|
|
|
+ pass
|
|
|
|
+ try:
|
|
|
|
+ return _setgroups_hack(groups[:max_groups])
|
|
|
|
+ except OSError, exc:
|
|
|
|
+ if exc.errno != errno.EPERM:
|
|
|
|
+ raise
|
|
|
|
+ if any(group not in groups for group in os.getgroups()):
|
|
|
|
+ # we shouldn't be allowed to change to this group.
|
|
|
|
+ raise
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def initgroups(uid, gid):
|
|
if grp and pwd:
|
|
if grp and pwd:
|
|
- user_name = pwd.getpwuid(uid)[0]
|
|
|
|
- user_groups = [gr.gr_gid for gr in grp.getgrall()
|
|
|
|
- if user_name in gr.gr_mem]
|
|
|
|
- os.setgroups(user_groups)
|
|
|
|
|
|
+ username = pwd.getpwuid(uid)[0]
|
|
|
|
+ if hasattr(os, "initgroups"): # Python 2.7+
|
|
|
|
+ return os.initgroups(username, gid)
|
|
|
|
+ groups = [gr.gr_gid for gr in grp.getgrall()
|
|
|
|
+ if username in gr.gr_mem]
|
|
|
|
+ setgroups(groups)
|
|
|
|
|
|
|
|
|
|
def setegid(gid):
|
|
def setegid(gid):
|
|
@@ -360,15 +399,15 @@ def setuid(uid):
|
|
os.setuid(parse_uid(uid))
|
|
os.setuid(parse_uid(uid))
|
|
|
|
|
|
|
|
|
|
-def set_effective_user(uid=None, gid=None):
|
|
|
|
|
|
+def maybe_drop_privileges(uid=None, gid=None):
|
|
"""Change process privileges to new user/group.
|
|
"""Change process privileges to new user/group.
|
|
|
|
|
|
- If UID and GID is set the effective user/group is set.
|
|
|
|
|
|
+ If UID and GID is specified, the real user/group is changed.
|
|
|
|
|
|
- If only UID is set, the effective user is set, and the group is
|
|
|
|
- set to the users primary group.
|
|
|
|
|
|
+ If only UID is specified, the real user is changed, and the group is
|
|
|
|
+ changed to the users primary group.
|
|
|
|
|
|
- If only GID is set, the effective group is set.
|
|
|
|
|
|
+ If only GID is specified, only the group is changed.
|
|
|
|
|
|
"""
|
|
"""
|
|
uid = uid and parse_uid(uid)
|
|
uid = uid and parse_uid(uid)
|
|
@@ -378,8 +417,12 @@ def set_effective_user(uid=None, gid=None):
|
|
# If GID isn't defined, get the primary GID of the user.
|
|
# If GID isn't defined, get the primary GID of the user.
|
|
if not gid and pwd:
|
|
if not gid and pwd:
|
|
gid = pwd.getpwuid(uid).pw_gid
|
|
gid = pwd.getpwuid(uid).pw_gid
|
|
|
|
+ # Must set the GID before initgroups(), as setgid()
|
|
|
|
+ # is known to zap the group list on some platforms.
|
|
setgid(gid)
|
|
setgid(gid)
|
|
- setgroups(uid)
|
|
|
|
|
|
+ initgroups(uid, gid)
|
|
|
|
+
|
|
|
|
+ # at last:
|
|
setuid(uid)
|
|
setuid(uid)
|
|
else:
|
|
else:
|
|
gid and setgid(gid)
|
|
gid and setgid(gid)
|