Python: How to get group ids of one username (like id -Gn )
Question:
getpwname
can only get the gid
of a username
.
import pwd
myGroupId = pwd.getpwnam(username).pw_gid
getgroups
can only get groups
of the script user.
import os
myGroupIds = os.getgroups()
How can I get all groups
of one arbitrary username
, like the id -Gn
command?
id -Gn `whoami`
Answers:
The following works assuming you are only interested in local users only, it will not work for things such as sssd
backed by a catalog server (for instance, ldap
).
#!/usr/bin/env python
import grp, pwd
user = "myname"
groups = [g.gr_name for g in grp.getgrall() if user in g.gr_mem]
gid = pwd.getpwnam(user).pw_gid
groups.append(grp.getgrgid(gid).gr_name)
print groups
The result of id -Gn
when the user belongs to one or more groups in which several group names map to the same gid
might not be the same as the posted answer. For instance if /etc/groups
is similar to this:
% ypcat group | grep mygroup
mygroup:*:66485:user1,user2,user3,...
mygroup1:*:66485:user101,user102,user103,...
mygroup2:*:66485:user201,user202,user203,...
...
And if the user is not listed in mygroup
but in mygroup<n>
, id -Gn
returns mygroup
but the posted answer returns mygroup<n>
.
It seems that in my environment, because UNIX groups can have hundreds or thousands of users, this is a common group management policy, although I don’t know exactly what is the user limit per group and why id -Gn
always returns mygroup
.
Nevertheless, with the code below I got a match with id -Gn
:
import pwd, grp
def getgroups(user):
gids = [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
gid = pwd.getpwnam(user).pw_gid
gids.append(grp.getgrgid(gid).gr_gid)
return [grp.getgrgid(gid).gr_name for gid in gids]
If you want the current user’s groups.
import os, grp
[grp.getgrgid(g).gr_name for g in os.getgroups()]
os.getgroups()
returns the list of gids of the current user.
grp.getgrgid(g)
returns details about a group
The only way I found to make this work correctly when having users non local to the system (e.g. ldap, sssd+ldap, freeIPA) without calling id in a subprocess is by calling the getgrouplist
c function (which is called by id eventually after going trough some abstractions):
#!/usr/bin/python
import grp, pwd, os
from ctypes import *
from ctypes.util import find_library
libc = cdll.LoadLibrary(find_library('libc'))
getgrouplist = libc.getgrouplist
# 50 groups should be enough, if not, we'll repeat the request with the correct nr bellow
ngroups = 50
getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint * ngroups), POINTER(c_int)]
getgrouplist.restype = c_int32
grouplist = (c_uint * ngroups)()
ngrouplist = c_int(ngroups)
user = pwd.getpwuid(2540485)
ct = getgrouplist(bytes(user.pw_name, 'UTF-8'), user.pw_gid, byref(grouplist), byref(ngrouplist))
# if 50 groups was not enough this will be -1, try again
# luckily the last call put the correct number of groups in ngrouplist
if ct < 0:
getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint *int(ngrouplist.value)), POINTER(c_int)]
grouplist = (c_uint * int(ngrouplist.value))()
ct = getgrouplist(user.pw_name, user.pw_gid, byref(grouplist), byref(ngrouplist))
for i in range(0, ct):
gid = grouplist[i]
print(grp.getgrgid(gid).gr_name)
Since Python 3.3:
import os
import pwd
uid = os.getuid()
user = pwd.getpwuid(uid)
gl = os.getgrouplist(user.pw_name, user.pw_gid)
print(gl)
getpwname
can only get the gid
of a username
.
import pwd
myGroupId = pwd.getpwnam(username).pw_gid
getgroups
can only get groups
of the script user.
import os
myGroupIds = os.getgroups()
How can I get all groups
of one arbitrary username
, like the id -Gn
command?
id -Gn `whoami`
The following works assuming you are only interested in local users only, it will not work for things such as sssd
backed by a catalog server (for instance, ldap
).
#!/usr/bin/env python
import grp, pwd
user = "myname"
groups = [g.gr_name for g in grp.getgrall() if user in g.gr_mem]
gid = pwd.getpwnam(user).pw_gid
groups.append(grp.getgrgid(gid).gr_name)
print groups
The result of id -Gn
when the user belongs to one or more groups in which several group names map to the same gid
might not be the same as the posted answer. For instance if /etc/groups
is similar to this:
% ypcat group | grep mygroup
mygroup:*:66485:user1,user2,user3,...
mygroup1:*:66485:user101,user102,user103,...
mygroup2:*:66485:user201,user202,user203,...
...
And if the user is not listed in mygroup
but in mygroup<n>
, id -Gn
returns mygroup
but the posted answer returns mygroup<n>
.
It seems that in my environment, because UNIX groups can have hundreds or thousands of users, this is a common group management policy, although I don’t know exactly what is the user limit per group and why id -Gn
always returns mygroup
.
Nevertheless, with the code below I got a match with id -Gn
:
import pwd, grp
def getgroups(user):
gids = [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
gid = pwd.getpwnam(user).pw_gid
gids.append(grp.getgrgid(gid).gr_gid)
return [grp.getgrgid(gid).gr_name for gid in gids]
If you want the current user’s groups.
import os, grp
[grp.getgrgid(g).gr_name for g in os.getgroups()]
os.getgroups()
returns the list of gids of the current user.
grp.getgrgid(g)
returns details about a group
The only way I found to make this work correctly when having users non local to the system (e.g. ldap, sssd+ldap, freeIPA) without calling id in a subprocess is by calling the getgrouplist
c function (which is called by id eventually after going trough some abstractions):
#!/usr/bin/python
import grp, pwd, os
from ctypes import *
from ctypes.util import find_library
libc = cdll.LoadLibrary(find_library('libc'))
getgrouplist = libc.getgrouplist
# 50 groups should be enough, if not, we'll repeat the request with the correct nr bellow
ngroups = 50
getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint * ngroups), POINTER(c_int)]
getgrouplist.restype = c_int32
grouplist = (c_uint * ngroups)()
ngrouplist = c_int(ngroups)
user = pwd.getpwuid(2540485)
ct = getgrouplist(bytes(user.pw_name, 'UTF-8'), user.pw_gid, byref(grouplist), byref(ngrouplist))
# if 50 groups was not enough this will be -1, try again
# luckily the last call put the correct number of groups in ngrouplist
if ct < 0:
getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint *int(ngrouplist.value)), POINTER(c_int)]
grouplist = (c_uint * int(ngrouplist.value))()
ct = getgrouplist(user.pw_name, user.pw_gid, byref(grouplist), byref(ngrouplist))
for i in range(0, ct):
gid = grouplist[i]
print(grp.getgrgid(gid).gr_name)
Since Python 3.3:
import os
import pwd
uid = os.getuid()
user = pwd.getpwuid(uid)
gl = os.getgrouplist(user.pw_name, user.pw_gid)
print(gl)