LCOV - code coverage report
Current view: | top level - Modules - pwdmodule.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 20 | 136 | 14.7 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 6 | 11 | 54.5 %
|  |  | Branches: | 6 | 66 | 9.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                 :         15 : get_pwd_state(PyObject *module)
          56                 :            : {
          57                 :         15 :     void *state = PyModule_GetState(module);
          58                 :            :     assert(state != NULL);
          59                 :         15 :     return (pwdmodulestate *)state;
          60                 :            : }
          61                 :            :
          62                 :            : static struct PyModuleDef pwdmodule;
          63                 :            :
          64                 :            : #define DEFAULT_BUFFER_SIZE 1024
          65                 :            :
          66                 :            : static void
          67                 :          0 : sets(PyObject *v, int i, const char* val)
          68                 :            : {
          69         [ #  # ]:          0 :   if (val) {
          70                 :          0 :       PyObject *o = PyUnicode_DecodeFSDefault(val);
          71                 :          0 :       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                 :          0 : }
          78                 :            :
          79                 :            : static PyObject *
          80                 :          0 : mkpwent(PyObject *module, struct passwd *p)
          81                 :            : {
          82                 :          0 :     int setIndex = 0;
          83                 :          0 :     PyObject *v = PyStructSequence_New(get_pwd_state(module)->StructPwdType);
          84         [ #  # ]:          0 :     if (v == NULL)
          85                 :          0 :         return NULL;
          86                 :            :
          87                 :            : #define SETS(i,val) sets(v, i, val)
          88                 :            :
          89                 :          0 :     SETS(setIndex++, p->pw_name);
          90                 :            : #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__)
          91                 :          0 :     SETS(setIndex++, p->pw_passwd);
          92                 :            : #else
          93                 :            :     SETS(setIndex++, "");
          94                 :            : #endif
          95                 :          0 :     PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid));
          96                 :          0 :     PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid));
          97                 :            : #if defined(HAVE_STRUCT_PASSWD_PW_GECOS)
          98                 :          0 :     SETS(setIndex++, p->pw_gecos);
          99                 :            : #else
         100                 :            :     SETS(setIndex++, "");
         101                 :            : #endif
         102                 :          0 :     SETS(setIndex++, p->pw_dir);
         103                 :          0 :     SETS(setIndex++, p->pw_shell);
         104                 :            :
         105                 :            : #undef SETS
         106                 :            :
         107         [ #  # ]:          0 :     if (PyErr_Occurred()) {
         108                 :          0 :         Py_XDECREF(v);
         109                 :          0 :         return NULL;
         110                 :            :     }
         111                 :            :
         112                 :          0 :     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                 :          0 : pwd_getpwuid(PyObject *module, PyObject *uidobj)
         128                 :            : /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/
         129                 :            : {
         130                 :          0 :     PyObject *retval = NULL;
         131                 :            :     uid_t uid;
         132                 :          0 :     int nomem = 0;
         133                 :            :     struct passwd *p;
         134                 :          0 :     char *buf = NULL, *buf2 = NULL;
         135                 :            :
         136         [ #  # ]:          0 :     if (!_Py_Uid_Converter(uidobj, &uid)) {
         137         [ #  # ]:          0 :         if (PyErr_ExceptionMatches(PyExc_OverflowError))
         138                 :          0 :             PyErr_Format(PyExc_KeyError,
         139                 :            :                          "getpwuid(): uid not found");
         140                 :          0 :         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                 :          0 :     Py_BEGIN_ALLOW_THREADS
         149                 :          0 :     bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
         150         [ #  # ]:          0 :     if (bufsize == -1) {
         151                 :          0 :         bufsize = DEFAULT_BUFFER_SIZE;
         152                 :            :     }
         153                 :            :
         154                 :            :     while(1) {
         155                 :          0 :         buf2 = PyMem_RawRealloc(buf, bufsize);
         156         [ #  # ]:          0 :         if (buf2 == NULL) {
         157                 :          0 :             p = NULL;
         158                 :          0 :             nomem = 1;
         159                 :          0 :             break;
         160                 :            :         }
         161                 :          0 :         buf = buf2;
         162                 :          0 :         status = getpwuid_r(uid, &pwd, buf, bufsize, &p);
         163         [ #  # ]:          0 :         if (status != 0) {
         164                 :          0 :             p = NULL;
         165                 :            :         }
         166   [ #  #  #  # ]:          0 :         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                 :          0 :     Py_END_ALLOW_THREADS
         177                 :            : #else
         178                 :            :     p = getpwuid(uid);
         179                 :            : #endif
         180         [ #  # ]:          0 :     if (p == NULL) {
         181                 :          0 :         PyMem_RawFree(buf);
         182         [ #  # ]:          0 :         if (nomem == 1) {
         183                 :          0 :             return PyErr_NoMemory();
         184                 :            :         }
         185                 :          0 :         PyObject *uid_obj = _PyLong_FromUid(uid);
         186         [ #  # ]:          0 :         if (uid_obj == NULL)
         187                 :          0 :             return NULL;
         188                 :          0 :         PyErr_Format(PyExc_KeyError,
         189                 :            :                      "getpwuid(): uid not found: %S", uid_obj);
         190                 :          0 :         Py_DECREF(uid_obj);
         191                 :          0 :         return NULL;
         192                 :            :     }
         193                 :          0 :     retval = mkpwent(module, p);
         194                 :            : #ifdef HAVE_GETPWUID_R
         195                 :          0 :     PyMem_RawFree(buf);
         196                 :            : #endif
         197                 :          0 :     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                 :          0 : pwd_getpwnam_impl(PyObject *module, PyObject *name)
         213                 :            : /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/
         214                 :            : {
         215                 :          0 :     char *buf = NULL, *buf2 = NULL, *name_chars;
         216                 :          0 :     int nomem = 0;
         217                 :            :     struct passwd *p;
         218                 :          0 :     PyObject *bytes, *retval = NULL;
         219                 :            :
         220         [ #  # ]:          0 :     if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
         221                 :          0 :         return NULL;
         222                 :            :     /* check for embedded null bytes */
         223         [ #  # ]:          0 :     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                 :          0 :     Py_BEGIN_ALLOW_THREADS
         232                 :          0 :     bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
         233         [ #  # ]:          0 :     if (bufsize == -1) {
         234                 :          0 :         bufsize = DEFAULT_BUFFER_SIZE;
         235                 :            :     }
         236                 :            :
         237                 :            :     while(1) {
         238                 :          0 :         buf2 = PyMem_RawRealloc(buf, bufsize);
         239         [ #  # ]:          0 :         if (buf2 == NULL) {
         240                 :          0 :             p = NULL;
         241                 :          0 :             nomem = 1;
         242                 :          0 :             break;
         243                 :            :         }
         244                 :          0 :         buf = buf2;
         245                 :          0 :         status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p);
         246         [ #  # ]:          0 :         if (status != 0) {
         247                 :          0 :             p = NULL;
         248                 :            :         }
         249   [ #  #  #  # ]:          0 :         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                 :          0 :     Py_END_ALLOW_THREADS
         260                 :            : #else
         261                 :            :     p = getpwnam(name_chars);
         262                 :            : #endif
         263         [ #  # ]:          0 :     if (p == NULL) {
         264         [ #  # ]:          0 :         if (nomem == 1) {
         265                 :          0 :             PyErr_NoMemory();
         266                 :            :         }
         267                 :            :         else {
         268                 :          0 :             PyErr_Format(PyExc_KeyError,
         269                 :            :                          "getpwnam(): name not found: %R", name);
         270                 :            :         }
         271                 :          0 :         goto out;
         272                 :            :     }
         273                 :          0 :     retval = mkpwent(module, p);
         274                 :          0 : out:
         275                 :          0 :     PyMem_RawFree(buf);
         276                 :          0 :     Py_DECREF(bytes);
         277                 :          0 :     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                 :          0 : pwd_getpwall_impl(PyObject *module)
         291                 :            : /*[clinic end generated code: output=4853d2f5a0afac8a input=d7ecebfd90219b85]*/
         292                 :            : {
         293                 :            :     PyObject *d;
         294                 :            :     struct passwd *p;
         295         [ #  # ]:          0 :     if ((d = PyList_New(0)) == NULL)
         296                 :          0 :         return NULL;
         297                 :          0 :     setpwent();
         298         [ #  # ]:          0 :     while ((p = getpwent()) != NULL) {
         299                 :          0 :         PyObject *v = mkpwent(module, p);
         300   [ #  #  #  # ]:          0 :         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                 :          0 :         Py_DECREF(v);
         307                 :            :     }
         308                 :          0 :     endpwent();
         309                 :          0 :     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                 :          1 : pwdmodule_exec(PyObject *module)
         324                 :            : {
         325                 :          1 :     pwdmodulestate *state = get_pwd_state(module);
         326                 :            :
         327                 :          1 :     state->StructPwdType = PyStructSequence_NewType(&struct_pwd_type_desc);
         328         [ -  + ]:          1 :     if (state->StructPwdType == NULL) {
         329                 :          0 :         return -1;
         330                 :            :     }
         331         [ -  + ]:          1 :     if (PyModule_AddType(module, state->StructPwdType) < 0) {
         332                 :          0 :         return -1;
         333                 :            :     }
         334                 :          1 :     return 0;
         335                 :            : }
         336                 :            :
         337                 :            : static PyModuleDef_Slot pwdmodule_slots[] = {
         338                 :            :     {Py_mod_exec, pwdmodule_exec},
         339                 :            :     {0, NULL}
         340                 :            : };
         341                 :            :
         342                 :          6 : static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
         343   [ +  -  -  + ]:          6 :     Py_VISIT(get_pwd_state(m)->StructPwdType);
         344                 :          6 :     return 0;
         345                 :            : }
         346                 :          2 : static int pwdmodule_clear(PyObject *m) {
         347         [ +  + ]:          2 :     Py_CLEAR(get_pwd_state(m)->StructPwdType);
         348                 :          2 :     return 0;
         349                 :            : }
         350                 :          1 : static void pwdmodule_free(void *m) {
         351                 :          1 :     pwdmodule_clear((PyObject *)m);
         352                 :          1 : }
         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                 :          1 : PyInit_pwd(void)
         369                 :            : {
         370                 :          1 :     return PyModuleDef_Init(&pwdmodule);
         371                 :            : }

Generated by: LCOV version 1.14