I've discovered some esoteric functionality with regards to how paste
serve drops privileges and I'd like to provide some information and
solicit feedback for a path forward.
When starting an application with paster serve as root (e.g. in order
to bind to a privileged port), the effective groups membership of the
processes as returned by 'os.getgroups()' is left as '' (i.e. root)
I don't really consider this a security issue myself, but others may
disagree, as a file that is readable/writable by the root GROUP will
still be accessible by the application started by paster serve as root
even after it "drops privileges" to another user as specified in the
Some folks will suggest that you simply call os.setgroups() to
remove all group membership permissions except that explicitly set
This is necessary and [probably] sufficient.
However, IMO, the better option is take advantage of
os.initgroups(user, gid), which will set the effective group
permissions for all groups of which the specified user is a member and
also the supplemental group id as provided (in this case from the
Unfortunately this system function only became directly available in >
2.7 (http://bugs.python.org/issue7333), but you can emulate the spirit
of the functionality with the grp module:
os.setgroups([e.gr_gid for e in grp.getgrall() if user in e.gr_mem] +
In paste.script.serve.change_user_group, you would perform the above
just before the call to os.setgid(gid).
I'd like to see the functionality of paster serve improved in this
regard. Would anyone else be interesting in patching this?
Alternatively suggest which patch would most likely to be accepted?
1) os.setgroups() is probably the quickest, but not as useful if you
need the extra permissions of all the user's groups.
2) check hasattr(os, 'initgroups') and call it when available,
otherwise call setgroups().
3) check hasattr(os, 'initgroups') and call it when available,
otherwise emulate initgroups using grp.getgrall().
4) always use setgroups and grp to find and set the groups of which
the specified user is a member.
For completeness, another option would be to ctype initgroups:
As an aside, currently, if a user, but no group is passed in on the
command line os.setgid is not called. I would suggest a better
default when group is not provided (as opposed to leaving the
effective gid as 0) would be to look for a group with the same name as
the user (grp.getgrnam(user)) and print a warning if unable to set a