Index: configure.in =================================================================== --- configure.in (revision 76628) +++ configure.in (working copy) @@ -2547,7 +2547,7 @@ clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \ gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ - kill killpg lchmod lchown lstat mkfifo mknod mktime \ + initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime \ mremap nice pathconf pause plock poll pthread_init \ putenv readlink realpath \ select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ Index: Doc/library/os.rst =================================================================== --- Doc/library/os.rst (revision 76628) +++ Doc/library/os.rst (working copy) @@ -136,6 +136,13 @@ Availability: Unix. +.. function:: initgroups(username, gid) + + Call the system initgroups() to initialize the group access list with all of + the groups of which the specified username is a member, plus the specified + group id. Availability: Unix. + + .. function:: getlogin() Return the name of the user logged in on the controlling terminal of the Index: Lib/test/test_posix.py =================================================================== --- Lib/test/test_posix.py (revision 76628) +++ Lib/test/test_posix.py (working copy) @@ -5,6 +5,7 @@ # Skip these tests if there is no posix module. posix = test_support.import_module('posix') +import errno import time import os import pwd @@ -83,6 +84,26 @@ new_group_ids = (current_group_ids[0]+1, -1, -1) self.assertRaises(OSError, posix.setresgid, *new_group_ids) + @unittest.skipUnless(hasattr(posix, 'initgroups')) + def test_initgroups(self): + # It takes a string and an integer; check that it raises a TypeError + # for other argument lists. + self.assertRaises(TypeError, posix.initgroups) + self.assertRaises(TypeError, posix.initgroups, None) + self.assertRaises(TypeError, posix.initgroups, 3, "foo") + self.assertRaises(TypeError, posix.initgroups, "foo", 3, object()) + + # If a non-privileged user invokes it, it should fail with OSError + # EPERM. + if os.getuid() != 0: + name = pwd.getpwuid(posix.getuid()).pw_nam + try: + posix.initgroups(name, 13) + except OSError, e: + self.assertEquals(e.errno, errno.EPERM) + else: + self.fail("Expected OSError to be raised by initgroups") + def test_statvfs(self): if hasattr(posix, 'statvfs'): self.assertTrue(posix.statvfs(os.curdir)) Index: Modules/posixmodule.c =================================================================== --- Modules/posixmodule.c (revision 76628) +++ Modules/posixmodule.c (working copy) @@ -3861,6 +3861,33 @@ } #endif +#ifdef HAVE_INITGROUPS +PyDoc_STRVAR(posix_initgroups__doc__, +"initgroups(username, gid) -> None\n\n\ +Call the system initgroups() to initialize the group access list with all of\n\ +the groups of which the specified username is a member, plus the specified\n\ +group id."); + +static PyObject * +posix_initgroups(PyObject *self, PyObject *args) +{ + char *username; + unsigned int igid; + gid_t gid; + + if (!PyArg_ParseTuple(args, "sI:initgroups", &username, &igid)) + return NULL; + + gid = igid; + + if (initgroups(username, gid) == -1) + return PyErr_SetFromErrno(PyExc_OSError); + + Py_INCREF(Py_None); + return Py_None; +} +#endif + #ifdef HAVE_GETPGID PyDoc_STRVAR(posix_getpgid__doc__, "getpgid(pid) -> pgid\n\n\ @@ -8629,6 +8656,9 @@ #ifdef HAVE_SETGROUPS {"setgroups", posix_setgroups, METH_O, posix_setgroups__doc__}, #endif /* HAVE_SETGROUPS */ +#ifdef HAVE_INITGROUPS + {"initgroups", posix_initgroups, METH_VARARGS, posix_initgroups__doc__}, +#endif /* HAVE_INITGROUPS */ #ifdef HAVE_GETPGID {"getpgid", posix_getpgid, METH_VARARGS, posix_getpgid__doc__}, #endif /* HAVE_GETPGID */ Index: pyconfig.h.in =================================================================== --- pyconfig.h.in (revision 76628) +++ pyconfig.h.in (working copy) @@ -301,6 +301,9 @@ /* Define to 1 if you have the `getpeername' function. */ #undef HAVE_GETPEERNAME +/* Define to 1 if you have the `initgroups' function. */ +#undef HAVE_INITGROUPS + /* Define to 1 if you have the `getpgid' function. */ #undef HAVE_GETPGID