LCOV - code coverage report
Current view: top level - Modules - pwdmodule.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 101 134 75.4 %
Date: 2022-07-20 13:12:14 Functions: 11 11 100.0 %
Branches: 39 66 59.1 %

           Branch data     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                 :       3534 : get_pwd_state(PyObject *module)
      56                 :            : {
      57                 :       3534 :     void *state = PyModule_GetState(module);
      58                 :            :     assert(state != NULL);
      59                 :       3534 :     return (pwdmodulestate *)state;
      60                 :            : }
      61                 :            : 
      62                 :            : static struct PyModuleDef pwdmodule;
      63                 :            : 
      64                 :            : #define DEFAULT_BUFFER_SIZE 1024
      65                 :            : 
      66                 :            : static void
      67                 :       5440 : sets(PyObject *v, int i, const char* val)
      68                 :            : {
      69         [ +  - ]:       5440 :   if (val) {
      70                 :       5440 :       PyObject *o = PyUnicode_DecodeFSDefault(val);
      71                 :       5440 :       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                 :       5440 : }
      78                 :            : 
      79                 :            : static PyObject *
      80                 :       1088 : mkpwent(PyObject *module, struct passwd *p)
      81                 :            : {
      82                 :       1088 :     int setIndex = 0;
      83                 :       1088 :     PyObject *v = PyStructSequence_New(get_pwd_state(module)->StructPwdType);
      84         [ -  + ]:       1088 :     if (v == NULL)
      85                 :          0 :         return NULL;
      86                 :            : 
      87                 :            : #define SETS(i,val) sets(v, i, val)
      88                 :            : 
      89                 :       1088 :     SETS(setIndex++, p->pw_name);
      90                 :            : #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__)
      91                 :       1088 :     SETS(setIndex++, p->pw_passwd);
      92                 :            : #else
      93                 :            :     SETS(setIndex++, "");
      94                 :            : #endif
      95                 :       1088 :     PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid));
      96                 :       1088 :     PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid));
      97                 :            : #if defined(HAVE_STRUCT_PASSWD_PW_GECOS)
      98                 :       1088 :     SETS(setIndex++, p->pw_gecos);
      99                 :            : #else
     100                 :            :     SETS(setIndex++, "");
     101                 :            : #endif
     102                 :       1088 :     SETS(setIndex++, p->pw_dir);
     103                 :       1088 :     SETS(setIndex++, p->pw_shell);
     104                 :            : 
     105                 :            : #undef SETS
     106                 :            : 
     107         [ -  + ]:       1088 :     if (PyErr_Occurred()) {
     108                 :          0 :         Py_XDECREF(v);
     109                 :          0 :         return NULL;
     110                 :            :     }
     111                 :            : 
     112                 :       1088 :     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                 :        655 : pwd_getpwuid(PyObject *module, PyObject *uidobj)
     128                 :            : /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/
     129                 :            : {
     130                 :        655 :     PyObject *retval = NULL;
     131                 :            :     uid_t uid;
     132                 :        655 :     int nomem = 0;
     133                 :            :     struct passwd *p;
     134                 :        655 :     char *buf = NULL, *buf2 = NULL;
     135                 :            : 
     136         [ +  + ]:        655 :     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                 :        651 :     Py_BEGIN_ALLOW_THREADS
     149                 :        651 :     bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
     150         [ -  + ]:        651 :     if (bufsize == -1) {
     151                 :          0 :         bufsize = DEFAULT_BUFFER_SIZE;
     152                 :            :     }
     153                 :            : 
     154                 :            :     while(1) {
     155                 :        651 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     156         [ -  + ]:        651 :         if (buf2 == NULL) {
     157                 :          0 :             p = NULL;
     158                 :          0 :             nomem = 1;
     159                 :          0 :             break;
     160                 :            :         }
     161                 :        651 :         buf = buf2;
     162                 :        651 :         status = getpwuid_r(uid, &pwd, buf, bufsize, &p);
     163         [ -  + ]:        651 :         if (status != 0) {
     164                 :          0 :             p = NULL;
     165                 :            :         }
     166   [ +  +  -  + ]:        651 :         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                 :        651 :     Py_END_ALLOW_THREADS
     177                 :            : #else
     178                 :            :     p = getpwuid(uid);
     179                 :            : #endif
     180         [ +  + ]:        651 :     if (p == NULL) {
     181                 :          1 :         PyMem_RawFree(buf);
     182         [ -  + ]:          1 :         if (nomem == 1) {
     183                 :            :             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                 :        650 :     retval = mkpwent(module, p);
     194                 :            : #ifdef HAVE_GETPWUID_R
     195                 :        650 :     PyMem_RawFree(buf);
     196                 :            : #endif
     197                 :        650 :     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                 :         87 : pwd_getpwnam_impl(PyObject *module, PyObject *name)
     213                 :            : /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/
     214                 :            : {
     215                 :         87 :     char *buf = NULL, *buf2 = NULL, *name_chars;
     216                 :         87 :     int nomem = 0;
     217                 :            :     struct passwd *p;
     218                 :         87 :     PyObject *bytes, *retval = NULL;
     219                 :            : 
     220         [ -  + ]:         87 :     if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
     221                 :          0 :         return NULL;
     222                 :            :     /* check for embedded null bytes */
     223         [ -  + ]:         87 :     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                 :         87 :     Py_BEGIN_ALLOW_THREADS
     232                 :         87 :     bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
     233         [ -  + ]:         87 :     if (bufsize == -1) {
     234                 :          0 :         bufsize = DEFAULT_BUFFER_SIZE;
     235                 :            :     }
     236                 :            : 
     237                 :            :     while(1) {
     238                 :         87 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     239         [ -  + ]:         87 :         if (buf2 == NULL) {
     240                 :          0 :             p = NULL;
     241                 :          0 :             nomem = 1;
     242                 :          0 :             break;
     243                 :            :         }
     244                 :         87 :         buf = buf2;
     245                 :         87 :         status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p);
     246         [ -  + ]:         87 :         if (status != 0) {
     247                 :          0 :             p = NULL;
     248                 :            :         }
     249   [ +  +  -  + ]:         87 :         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                 :         87 :     Py_END_ALLOW_THREADS
     260                 :            : #else
     261                 :            :     p = getpwnam(name_chars);
     262                 :            : #endif
     263         [ +  + ]:         87 :     if (p == NULL) {
     264         [ -  + ]:          9 :         if (nomem == 1) {
     265                 :            :             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                 :         78 :     retval = mkpwent(module, p);
     274                 :         87 : out:
     275                 :         87 :     PyMem_RawFree(buf);
     276                 :         87 :     Py_DECREF(bytes);
     277                 :         87 :     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         [ +  + ]:        366 :     while ((p = getpwent()) != NULL) {
     299                 :        360 :         PyObject *v = mkpwent(module, p);
     300   [ +  -  -  + ]:        360 :         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                 :        360 :         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                 :         93 : pwdmodule_exec(PyObject *module)
     324                 :            : {
     325                 :         93 :     pwdmodulestate *state = get_pwd_state(module);
     326                 :            : 
     327                 :         93 :     state->StructPwdType = PyStructSequence_NewType(&struct_pwd_type_desc);
     328         [ -  + ]:         93 :     if (state->StructPwdType == NULL) {
     329                 :          0 :         return -1;
     330                 :            :     }
     331         [ -  + ]:         93 :     if (PyModule_AddType(module, state->StructPwdType) < 0) {
     332                 :          0 :         return -1;
     333                 :            :     }
     334                 :         93 :     return 0;
     335                 :            : }
     336                 :            : 
     337                 :            : static PyModuleDef_Slot pwdmodule_slots[] = {
     338                 :            :     {Py_mod_exec, pwdmodule_exec},
     339                 :            :     {0, NULL}
     340                 :            : };
     341                 :            : 
     342                 :       1040 : static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
     343   [ +  -  -  + ]:       1040 :     Py_VISIT(get_pwd_state(m)->StructPwdType);
     344                 :       1040 :     return 0;
     345                 :            : }
     346                 :        180 : static int pwdmodule_clear(PyObject *m) {
     347         [ +  + ]:        180 :     Py_CLEAR(get_pwd_state(m)->StructPwdType);
     348                 :        180 :     return 0;
     349                 :            : }
     350                 :         93 : static void pwdmodule_free(void *m) {
     351                 :         93 :     pwdmodule_clear((PyObject *)m);
     352                 :         93 : }
     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                 :         93 : PyInit_pwd(void)
     369                 :            : {
     370                 :         93 :     return PyModuleDef_Init(&pwdmodule);
     371                 :            : }

Generated by: LCOV version 1.14