Index: Modules/posixmodule.c =================================================================== --- Modules/posixmodule.c (revision 80783) +++ Modules/posixmodule.c (working copy) @@ -3851,24 +3851,48 @@ { PyObject *result = NULL; -#ifdef NGROUPS_MAX +#if defined(NGROUPS_MAX) && (NGROUPS_MAX <= 64) #define MAX_GROUPS NGROUPS_MAX #else /* defined to be 16 on Solaris7, so this should be a small number */ #define MAX_GROUPS 64 #endif gid_t grouplist[MAX_GROUPS]; + gid_t* alt_grouplist = NULL; int n; n = getgroups(MAX_GROUPS, grouplist); - if (n < 0) - posix_error(); - else { - result = PyList_New(n); - if (result != NULL) { + if (n < 0) { + if (errno == EINVAL) { + n = getgroups(0, grouplist); + if (n == -1) { + return posix_error(); + } + if (n == 0) { + alt_grouplist = grouplist; + } else { + alt_grouplist = PyMem_Malloc(n * sizeof(gid_t)); + if (alt_grouplist == NULL) { + errno = EINVAL; + return posix_error(); + } + n = getgroups(n, grouplist); + if (n == -1) { + PyMem_Free(alt_grouplist); + return posix_error(); + } + } + } else { + return posix_error(); + } + } else { + alt_grouplist = grouplist; + } + result = PyList_New(n); + if (result != NULL) { int i; for (i = 0; i < n; ++i) { - PyObject *o = PyInt_FromLong((long)grouplist[i]); + PyObject *o = PyInt_FromLong((long)alt_grouplist[i]); if (o == NULL) { Py_DECREF(result); result = NULL; @@ -3876,10 +3900,13 @@ } PyList_SET_ITEM(result, i, o); } - } - } + } - return result; + if (alt_grouplist != grouplist) { + PyMem_Free(alt_grouplist); + } + + return result; } #endif Index: Lib/test/test_posix.py =================================================================== --- Lib/test/test_posix.py (revision 80783) +++ Lib/test/test_posix.py (working copy) @@ -12,6 +12,7 @@ import shutil import unittest import warnings +import sys warnings.filterwarnings('ignore', '.* potential security risk .*', @@ -356,10 +357,78 @@ finally: os.chdir(curdir) shutil.rmtree(base_path) + + def test_getgroups(self): + with os.popen('id -G') as idg: + groups = idg.read().strip() + if not groups: + raise SkipTest("need working 'id -G'") + self.assertListEqual(map(int, groups.split()), posix.getgroups()) +class PosixGroupsTester(unittest.TestCase): + + def setUp(self): + if posix.getuid() != 0: + raise unittest.SkipTest("not enough privileges") + if not hasattr(posix, 'getgroups'): + raise unittest.SkipTest("need posix.getgroups") + if sys.platform == 'darwin': + raise unittest.SkipTest("getgroups(2) is broken on OSX") + self.saved_groups = posix.getgroups() + def tearDown(self): + if hasattr(posix, 'setgroups'): + posix.setgroups(self.saved_groups) + elif hasattr(posix, 'initgroups'): + name = pwd.getpwuid(posix.getuid()).pw_name + posix.initgroups(name, self.saved_groups[0]) + + @unittest.skipUnless(hasattr(posix, 'initgroups'), + "test needs posix.initgroups()") + def test_initgroups(self): + # find missing group + + groups = sorted(self.saved_groups) + for g1,g2 in zip(groups[:-1], groups[1:]): + g = g1 + 1 + if g < g2: + break + else: + g = g2 + 1 + name = pwd.getpwuid(posix.getuid()).pw_name + posix.initgroups(name, g) + self.assertIn(g, posix.getgroups()) + + @unittest.skipUnless(hasattr(posix, 'setgroups'), + "test needs posix.setgroups()") + def test_setgroups(self): + for groups in [[0], range(16)]: + posix.setgroups(groups) + self.assertListEqual(groups, posix.getgroups()) + +class SystemGroupTester (unittest.TestCase): + def setUp(self): + if not hasattr(posix, 'getgroups'): + raise unittest.SkipTest("need posix.getgroups") + if sys.platform != 'darwin': + raise unittest.SkipTest("test on darwin only") + + def test_getgrps_vs_id(self): + import subprocess + groups = posix.getgroups() + + p = subprocess.Popen(["id", "-G"], + stdout=subprocess.PIPE) + stdout, _ = p.communicate() + sts = p.wait() + self.assertEqual(sts, 0) + + id_groups = map(int, stdout.split()) + self.assertEquals(set(groups), set(id_groups)) + + def test_main(): - test_support.run_unittest(PosixTester) + test_support.run_unittest(PosixTester, PosixGroupsTester, SystemGroupTester) if __name__ == '__main__': test_main()