LCOV - code coverage report
Current view: top level - Modules - pwdmodule.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 102 137 74.5 %
Date: 2022-07-07 18:19:46 Functions: 11 11 100.0 %

          Line data    Source code
       1             : 
       2             : /* UNIX password file access module */
       3             : 
       4             : #include "Python.h"
       5             : #include "posixmodule.h"
       6             : 
       7             : #include <pwd.h>
       8             : 
       9             : #include "clinic/pwdmodule.c.h"
      10             : /*[clinic input]
      11             : module pwd
      12             : [clinic start generated code]*/
      13             : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=60f628ef356b97b6]*/
      14             : 
      15             : static PyStructSequence_Field struct_pwd_type_fields[] = {
      16             :     {"pw_name", "user name"},
      17             :     {"pw_passwd", "password"},
      18             :     {"pw_uid", "user id"},
      19             :     {"pw_gid", "group id"},
      20             :     {"pw_gecos", "real name"},
      21             :     {"pw_dir", "home directory"},
      22             :     {"pw_shell", "shell program"},
      23             :     {0}
      24             : };
      25             : 
      26             : PyDoc_STRVAR(struct_passwd__doc__,
      27             : "pwd.struct_passwd: Results from getpw*() routines.\n\n\
      28             : This object may be accessed either as a tuple of\n\
      29             :   (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell)\n\
      30             : or via the object attributes as named in the above tuple.");
      31             : 
      32             : static PyStructSequence_Desc struct_pwd_type_desc = {
      33             :     "pwd.struct_passwd",
      34             :     struct_passwd__doc__,
      35             :     struct_pwd_type_fields,
      36             :     7,
      37             : };
      38             : 
      39             : PyDoc_STRVAR(pwd__doc__,
      40             : "This module provides access to the Unix password database.\n\
      41             : It is available on all Unix versions.\n\
      42             : \n\
      43             : Password database entries are reported as 7-tuples containing the following\n\
      44             : items from the password database (see `<pwd.h>'), in order:\n\
      45             : pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell.\n\
      46             : The uid and gid items are integers, all others are strings. An\n\
      47             : exception is raised if the entry asked for cannot be found.");
      48             : 
      49             : 
      50             : typedef struct {
      51             :     PyTypeObject *StructPwdType;
      52             : } pwdmodulestate;
      53             : 
      54             : static inline pwdmodulestate*
      55        3522 : get_pwd_state(PyObject *module)
      56             : {
      57        3522 :     void *state = PyModule_GetState(module);
      58        3522 :     assert(state != NULL);
      59        3522 :     return (pwdmodulestate *)state;
      60             : }
      61             : 
      62             : static struct PyModuleDef pwdmodule;
      63             : 
      64             : #define DEFAULT_BUFFER_SIZE 1024
      65             : 
      66             : static void
      67        4640 : sets(PyObject *v, int i, const char* val)
      68             : {
      69        4640 :   if (val) {
      70        4640 :       PyObject *o = PyUnicode_DecodeFSDefault(val);
      71        4640 :       PyStructSequence_SET_ITEM(v, i, o);
      72             :   }
      73             :   else {
      74           0 :       PyStructSequence_SET_ITEM(v, i, Py_None);
      75           0 :       Py_INCREF(Py_None);
      76             :   }
      77        4640 : }
      78             : 
      79             : static PyObject *
      80         928 : mkpwent(PyObject *module, struct passwd *p)
      81             : {
      82         928 :     int setIndex = 0;
      83         928 :     PyObject *v = PyStructSequence_New(get_pwd_state(module)->StructPwdType);
      84         928 :     if (v == NULL)
      85           0 :         return NULL;
      86             : 
      87             : #define SETS(i,val) sets(v, i, val)
      88             : 
      89         928 :     SETS(setIndex++, p->pw_name);
      90             : #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__)
      91         928 :     SETS(setIndex++, p->pw_passwd);
      92             : #else
      93             :     SETS(setIndex++, "");
      94             : #endif
      95         928 :     PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid));
      96         928 :     PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid));
      97             : #if defined(HAVE_STRUCT_PASSWD_PW_GECOS)
      98         928 :     SETS(setIndex++, p->pw_gecos);
      99             : #else
     100             :     SETS(setIndex++, "");
     101             : #endif
     102         928 :     SETS(setIndex++, p->pw_dir);
     103         928 :     SETS(setIndex++, p->pw_shell);
     104             : 
     105             : #undef SETS
     106             : 
     107         928 :     if (PyErr_Occurred()) {
     108           0 :         Py_XDECREF(v);
     109           0 :         return NULL;
     110             :     }
     111             : 
     112         928 :     return v;
     113             : }
     114             : 
     115             : /*[clinic input]
     116             : pwd.getpwuid
     117             : 
     118             :     uidobj: object
     119             :     /
     120             : 
     121             : Return the password database entry for the given numeric user ID.
     122             : 
     123             : See `help(pwd)` for more on password database entries.
     124             : [clinic start generated code]*/
     125             : 
     126             : static PyObject *
     127         635 : pwd_getpwuid(PyObject *module, PyObject *uidobj)
     128             : /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/
     129             : {
     130         635 :     PyObject *retval = NULL;
     131             :     uid_t uid;
     132         635 :     int nomem = 0;
     133             :     struct passwd *p;
     134         635 :     char *buf = NULL, *buf2 = NULL;
     135             : 
     136         635 :     if (!_Py_Uid_Converter(uidobj, &uid)) {
     137           4 :         if (PyErr_ExceptionMatches(PyExc_OverflowError))
     138           3 :             PyErr_Format(PyExc_KeyError,
     139             :                          "getpwuid(): uid not found");
     140           4 :         return NULL;
     141             :     }
     142             : #ifdef HAVE_GETPWUID_R
     143             :     int status;
     144             :     Py_ssize_t bufsize;
     145             :     /* Note: 'pwd' will be used via pointer 'p' on getpwuid_r success. */
     146             :     struct passwd pwd;
     147             : 
     148         631 :     Py_BEGIN_ALLOW_THREADS
     149         631 :     bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
     150         631 :     if (bufsize == -1) {
     151           0 :         bufsize = DEFAULT_BUFFER_SIZE;
     152             :     }
     153             : 
     154             :     while(1) {
     155         631 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     156         631 :         if (buf2 == NULL) {
     157           0 :             p = NULL;
     158           0 :             nomem = 1;
     159           0 :             break;
     160             :         }
     161         631 :         buf = buf2;
     162         631 :         status = getpwuid_r(uid, &pwd, buf, bufsize, &p);
     163         631 :         if (status != 0) {
     164           0 :             p = NULL;
     165             :         }
     166         631 :         if (p != NULL || status != ERANGE) {
     167             :             break;
     168             :         }
     169           0 :         if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
     170           0 :             nomem = 1;
     171           0 :             break;
     172             :         }
     173           0 :         bufsize <<= 1;
     174             :     }
     175             : 
     176         631 :     Py_END_ALLOW_THREADS
     177             : #else
     178             :     p = getpwuid(uid);
     179             : #endif
     180         631 :     if (p == NULL) {
     181           1 :         PyMem_RawFree(buf);
     182           1 :         if (nomem == 1) {
     183           0 :             return PyErr_NoMemory();
     184             :         }
     185           1 :         PyObject *uid_obj = _PyLong_FromUid(uid);
     186           1 :         if (uid_obj == NULL)
     187           0 :             return NULL;
     188           1 :         PyErr_Format(PyExc_KeyError,
     189             :                      "getpwuid(): uid not found: %S", uid_obj);
     190           1 :         Py_DECREF(uid_obj);
     191           1 :         return NULL;
     192             :     }
     193         630 :     retval = mkpwent(module, p);
     194             : #ifdef HAVE_GETPWUID_R
     195         630 :     PyMem_RawFree(buf);
     196             : #endif
     197         630 :     return retval;
     198             : }
     199             : 
     200             : /*[clinic input]
     201             : pwd.getpwnam
     202             : 
     203             :     name: unicode
     204             :     /
     205             : 
     206             : Return the password database entry for the given user name.
     207             : 
     208             : See `help(pwd)` for more on password database entries.
     209             : [clinic start generated code]*/
     210             : 
     211             : static PyObject *
     212          67 : pwd_getpwnam_impl(PyObject *module, PyObject *name)
     213             : /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/
     214             : {
     215          67 :     char *buf = NULL, *buf2 = NULL, *name_chars;
     216          67 :     int nomem = 0;
     217             :     struct passwd *p;
     218          67 :     PyObject *bytes, *retval = NULL;
     219             : 
     220          67 :     if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
     221           0 :         return NULL;
     222             :     /* check for embedded null bytes */
     223          67 :     if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
     224           0 :         goto out;
     225             : #ifdef HAVE_GETPWNAM_R
     226             :     int status;
     227             :     Py_ssize_t bufsize;
     228             :     /* Note: 'pwd' will be used via pointer 'p' on getpwnam_r success. */
     229             :     struct passwd pwd;
     230             : 
     231          67 :     Py_BEGIN_ALLOW_THREADS
     232          67 :     bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
     233          67 :     if (bufsize == -1) {
     234           0 :         bufsize = DEFAULT_BUFFER_SIZE;
     235             :     }
     236             : 
     237             :     while(1) {
     238          67 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     239          67 :         if (buf2 == NULL) {
     240           0 :             p = NULL;
     241           0 :             nomem = 1;
     242           0 :             break;
     243             :         }
     244          67 :         buf = buf2;
     245          67 :         status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p);
     246          67 :         if (status != 0) {
     247           0 :             p = NULL;
     248             :         }
     249          67 :         if (p != NULL || status != ERANGE) {
     250             :             break;
     251             :         }
     252           0 :         if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
     253           0 :             nomem = 1;
     254           0 :             break;
     255             :         }
     256           0 :         bufsize <<= 1;
     257             :     }
     258             : 
     259          67 :     Py_END_ALLOW_THREADS
     260             : #else
     261             :     p = getpwnam(name_chars);
     262             : #endif
     263          67 :     if (p == NULL) {
     264           9 :         if (nomem == 1) {
     265           0 :             PyErr_NoMemory();
     266             :         }
     267             :         else {
     268           9 :             PyErr_Format(PyExc_KeyError,
     269             :                          "getpwnam(): name not found: %R", name);
     270             :         }
     271           9 :         goto out;
     272             :     }
     273          58 :     retval = mkpwent(module, p);
     274          67 : out:
     275          67 :     PyMem_RawFree(buf);
     276          67 :     Py_DECREF(bytes);
     277          67 :     return retval;
     278             : }
     279             : 
     280             : #ifdef HAVE_GETPWENT
     281             : /*[clinic input]
     282             : pwd.getpwall
     283             : 
     284             : Return a list of all available password database entries, in arbitrary order.
     285             : 
     286             : See help(pwd) for more on password database entries.
     287             : [clinic start generated code]*/
     288             : 
     289             : static PyObject *
     290           6 : pwd_getpwall_impl(PyObject *module)
     291             : /*[clinic end generated code: output=4853d2f5a0afac8a input=d7ecebfd90219b85]*/
     292             : {
     293             :     PyObject *d;
     294             :     struct passwd *p;
     295           6 :     if ((d = PyList_New(0)) == NULL)
     296           0 :         return NULL;
     297           6 :     setpwent();
     298         246 :     while ((p = getpwent()) != NULL) {
     299         240 :         PyObject *v = mkpwent(module, p);
     300         240 :         if (v == NULL || PyList_Append(d, v) != 0) {
     301           0 :             Py_XDECREF(v);
     302           0 :             Py_DECREF(d);
     303           0 :             endpwent();
     304           0 :             return NULL;
     305             :         }
     306         240 :         Py_DECREF(v);
     307             :     }
     308           6 :     endpwent();
     309           6 :     return d;
     310             : }
     311             : #endif
     312             : 
     313             : static PyMethodDef pwd_methods[] = {
     314             :     PWD_GETPWUID_METHODDEF
     315             :     PWD_GETPWNAM_METHODDEF
     316             : #ifdef HAVE_GETPWENT
     317             :     PWD_GETPWALL_METHODDEF
     318             : #endif
     319             :     {NULL,              NULL}           /* sentinel */
     320             : };
     321             : 
     322             : static int
     323          92 : pwdmodule_exec(PyObject *module)
     324             : {
     325          92 :     pwdmodulestate *state = get_pwd_state(module);
     326             : 
     327          92 :     state->StructPwdType = PyStructSequence_NewType(&struct_pwd_type_desc);
     328          92 :     if (state->StructPwdType == NULL) {
     329           0 :         return -1;
     330             :     }
     331          92 :     if (PyModule_AddType(module, state->StructPwdType) < 0) {
     332           0 :         return -1;
     333             :     }
     334          92 :     return 0;
     335             : }
     336             : 
     337             : static PyModuleDef_Slot pwdmodule_slots[] = {
     338             :     {Py_mod_exec, pwdmodule_exec},
     339             :     {0, NULL}
     340             : };
     341             : 
     342        1116 : static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
     343        1116 :     Py_VISIT(get_pwd_state(m)->StructPwdType);
     344        1116 :     return 0;
     345             : }
     346         178 : static int pwdmodule_clear(PyObject *m) {
     347         178 :     Py_CLEAR(get_pwd_state(m)->StructPwdType);
     348         178 :     return 0;
     349             : }
     350          92 : static void pwdmodule_free(void *m) {
     351          92 :     pwdmodule_clear((PyObject *)m);
     352          92 : }
     353             : 
     354             : static struct PyModuleDef pwdmodule = {
     355             :     PyModuleDef_HEAD_INIT,
     356             :     .m_name = "pwd",
     357             :     .m_doc = pwd__doc__,
     358             :     .m_size = sizeof(pwdmodulestate),
     359             :     .m_methods = pwd_methods,
     360             :     .m_slots = pwdmodule_slots,
     361             :     .m_traverse = pwdmodule_traverse,
     362             :     .m_clear = pwdmodule_clear,
     363             :     .m_free = pwdmodule_free,
     364             : };
     365             : 
     366             : 
     367             : PyMODINIT_FUNC
     368          92 : PyInit_pwd(void)
     369             : {
     370          92 :     return PyModuleDef_Init(&pwdmodule);
     371             : }

Generated by: LCOV version 1.14