11
22/* UNIX password file access module */
33
4- // Need limited C API version 3.13 for PyMem_RawRealloc()
5- #include "pyconfig.h" // Py_GIL_DISABLED
6- #ifndef Py_GIL_DISABLED
7- # define Py_LIMITED_API 0x030d0000
8- #endif
9-
104#include "Python.h"
115#include "posixmodule.h"
126
@@ -69,6 +63,11 @@ get_pwd_state(PyObject *module)
6963
7064static struct PyModuleDef pwdmodule ;
7165
66+ /* Mutex to protect calls to getpwuid(), getpwnam(), and getpwent().
67+ * These functions return pointer to static data structure, which
68+ * may be overwritten by any subsequent calls. */
69+ static PyMutex pwd_db_mutex = {0 };
70+
7271#define DEFAULT_BUFFER_SIZE 1024
7372
7473static PyObject *
@@ -182,9 +181,15 @@ pwd_getpwuid(PyObject *module, PyObject *uidobj)
182181
183182 Py_END_ALLOW_THREADS
184183#else
184+ PyMutex_Lock (& pwd_db_mutex );
185+ // The getpwuid() function is not required to be thread-safe.
186+ // https://pubs.opengroup.org/onlinepubs/009604499/functions/getpwuid.html
185187 p = getpwuid (uid );
186188#endif
187189 if (p == NULL ) {
190+ #ifndef HAVE_GETPWUID_R
191+ PyMutex_Unlock (& pwd_db_mutex );
192+ #endif
188193 PyMem_RawFree (buf );
189194 if (nomem == 1 ) {
190195 return PyErr_NoMemory ();
@@ -200,6 +205,8 @@ pwd_getpwuid(PyObject *module, PyObject *uidobj)
200205 retval = mkpwent (module , p );
201206#ifdef HAVE_GETPWUID_R
202207 PyMem_RawFree (buf );
208+ #else
209+ PyMutex_Unlock (& pwd_db_mutex );
203210#endif
204211 return retval ;
205212}
@@ -265,9 +272,15 @@ pwd_getpwnam_impl(PyObject *module, PyObject *name)
265272
266273 Py_END_ALLOW_THREADS
267274#else
275+ PyMutex_Lock (& pwd_db_mutex );
276+ // The getpwnam() function is not required to be thread-safe.
277+ // https://pubs.opengroup.org/onlinepubs/009604599/functions/getpwnam.html
268278 p = getpwnam (name_chars );
269279#endif
270280 if (p == NULL ) {
281+ #ifndef HAVE_GETPWNAM_R
282+ PyMutex_Unlock (& pwd_db_mutex );
283+ #endif
271284 if (nomem == 1 ) {
272285 PyErr_NoMemory ();
273286 }
@@ -278,6 +291,9 @@ pwd_getpwnam_impl(PyObject *module, PyObject *name)
278291 goto out ;
279292 }
280293 retval = mkpwent (module , p );
294+ #ifndef HAVE_GETPWNAM_R
295+ PyMutex_Unlock (& pwd_db_mutex );
296+ #endif
281297out :
282298 PyMem_RawFree (buf );
283299 Py_DECREF (bytes );
@@ -302,12 +318,12 @@ pwd_getpwall_impl(PyObject *module)
302318 if ((d = PyList_New (0 )) == NULL )
303319 return NULL ;
304320
305- #ifdef Py_GIL_DISABLED
306- static PyMutex getpwall_mutex = {0 };
307- PyMutex_Lock (& getpwall_mutex );
308- #endif
321+ PyMutex_Lock (& pwd_db_mutex );
309322 int failure = 0 ;
310323 PyObject * v = NULL ;
324+ // The setpwent(), getpwent() and endpwent() functions are not required to
325+ // be thread-safe.
326+ // https://pubs.opengroup.org/onlinepubs/009696799/functions/setpwent.html
311327 setpwent ();
312328 while ((p = getpwent ()) != NULL ) {
313329 v = mkpwent (module , p );
@@ -321,9 +337,7 @@ pwd_getpwall_impl(PyObject *module)
321337
322338done :
323339 endpwent ();
324- #ifdef Py_GIL_DISABLED
325- PyMutex_Unlock (& getpwall_mutex );
326- #endif
340+ PyMutex_Unlock (& pwd_db_mutex );
327341 if (failure ) {
328342 Py_XDECREF (v );
329343 Py_CLEAR (d );
0 commit comments