LCOV - code coverage report
Current view: top level - Modules - grpmodule.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 98 136 72.1 %
Date: 2022-07-20 13:12:14 Functions: 10 10 100.0 %
Branches: 43 72 59.7 %

           Branch data     Line data    Source code
       1                 :            : 
       2                 :            : /* UNIX group file access module */
       3                 :            : 
       4                 :            : #include "Python.h"
       5                 :            : #include "posixmodule.h"
       6                 :            : 
       7                 :            : #include <grp.h>
       8                 :            : 
       9                 :            : #include "clinic/grpmodule.c.h"
      10                 :            : /*[clinic input]
      11                 :            : module grp
      12                 :            : [clinic start generated code]*/
      13                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=cade63f2ed1bd9f8]*/
      14                 :            : 
      15                 :            : static PyStructSequence_Field struct_group_type_fields[] = {
      16                 :            :    {"gr_name", "group name"},
      17                 :            :    {"gr_passwd", "password"},
      18                 :            :    {"gr_gid", "group id"},
      19                 :            :    {"gr_mem", "group members"},
      20                 :            :    {0}
      21                 :            : };
      22                 :            : 
      23                 :            : PyDoc_STRVAR(struct_group__doc__,
      24                 :            : "grp.struct_group: Results from getgr*() routines.\n\n\
      25                 :            : This object may be accessed either as a tuple of\n\
      26                 :            :   (gr_name,gr_passwd,gr_gid,gr_mem)\n\
      27                 :            : or via the object attributes as named in the above tuple.\n");
      28                 :            : 
      29                 :            : static PyStructSequence_Desc struct_group_type_desc = {
      30                 :            :    "grp.struct_group",
      31                 :            :    struct_group__doc__,
      32                 :            :    struct_group_type_fields,
      33                 :            :    4,
      34                 :            : };
      35                 :            : 
      36                 :            : 
      37                 :            : typedef struct {
      38                 :            :   PyTypeObject *StructGrpType;
      39                 :            : } grpmodulestate;
      40                 :            : 
      41                 :            : static inline grpmodulestate*
      42                 :       3135 : get_grp_state(PyObject *module)
      43                 :            : {
      44                 :       3135 :     void *state = PyModule_GetState(module);
      45                 :            :     assert(state != NULL);
      46                 :       3135 :     return (grpmodulestate *)state;
      47                 :            : }
      48                 :            : 
      49                 :            : static struct PyModuleDef grpmodule;
      50                 :            : 
      51                 :            : #define DEFAULT_BUFFER_SIZE 1024
      52                 :            : 
      53                 :            : static PyObject *
      54                 :       1185 : mkgrent(PyObject *module, struct group *p)
      55                 :            : {
      56                 :       1185 :     int setIndex = 0;
      57                 :            :     PyObject *v, *w;
      58                 :            :     char **member;
      59                 :            : 
      60                 :       1185 :     v = PyStructSequence_New(get_grp_state(module)->StructGrpType);
      61         [ -  + ]:       1185 :     if (v == NULL)
      62                 :          0 :         return NULL;
      63                 :            : 
      64         [ -  + ]:       1185 :     if ((w = PyList_New(0)) == NULL) {
      65                 :          0 :         Py_DECREF(v);
      66                 :          0 :         return NULL;
      67                 :            :     }
      68         [ +  + ]:       1251 :     for (member = p->gr_mem; *member != NULL; member++) {
      69                 :         66 :         PyObject *x = PyUnicode_DecodeFSDefault(*member);
      70   [ +  -  -  + ]:         66 :         if (x == NULL || PyList_Append(w, x) != 0) {
      71                 :          0 :             Py_XDECREF(x);
      72                 :          0 :             Py_DECREF(w);
      73                 :          0 :             Py_DECREF(v);
      74                 :          0 :             return NULL;
      75                 :            :         }
      76                 :         66 :         Py_DECREF(x);
      77                 :            :     }
      78                 :            : 
      79                 :            : #define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
      80                 :       1185 :     SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
      81         [ +  - ]:       1185 :     if (p->gr_passwd)
      82                 :       1185 :             SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
      83                 :            :     else {
      84                 :          0 :             SET(setIndex++, Py_None);
      85                 :          0 :             Py_INCREF(Py_None);
      86                 :            :     }
      87                 :       1185 :     SET(setIndex++, _PyLong_FromGid(p->gr_gid));
      88                 :       1185 :     SET(setIndex++, w);
      89                 :            : #undef SET
      90                 :            : 
      91         [ -  + ]:       1185 :     if (PyErr_Occurred()) {
      92                 :          0 :         Py_DECREF(v);
      93                 :          0 :         return NULL;
      94                 :            :     }
      95                 :            : 
      96                 :       1185 :     return v;
      97                 :            : }
      98                 :            : 
      99                 :            : /*[clinic input]
     100                 :            : grp.getgrgid
     101                 :            : 
     102                 :            :     id: object
     103                 :            : 
     104                 :            : Return the group database entry for the given numeric group ID.
     105                 :            : 
     106                 :            : If id is not valid, raise KeyError.
     107                 :            : [clinic start generated code]*/
     108                 :            : 
     109                 :            : static PyObject *
     110                 :        675 : grp_getgrgid_impl(PyObject *module, PyObject *id)
     111                 :            : /*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
     112                 :            : {
     113                 :        675 :     PyObject *retval = NULL;
     114                 :        675 :     int nomem = 0;
     115                 :        675 :     char *buf = NULL, *buf2 = NULL;
     116                 :            :     gid_t gid;
     117                 :            :     struct group *p;
     118                 :            : 
     119         [ +  + ]:        675 :     if (!_Py_Gid_Converter(id, &gid)) {
     120                 :          2 :         return NULL;
     121                 :            :     }
     122                 :            : #ifdef HAVE_GETGRGID_R
     123                 :            :     int status;
     124                 :            :     Py_ssize_t bufsize;
     125                 :            :     /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
     126                 :            :     struct group grp;
     127                 :            : 
     128                 :        673 :     Py_BEGIN_ALLOW_THREADS
     129                 :        673 :     bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
     130         [ -  + ]:        673 :     if (bufsize == -1) {
     131                 :          0 :         bufsize = DEFAULT_BUFFER_SIZE;
     132                 :            :     }
     133                 :            : 
     134                 :            :     while (1) {
     135                 :        673 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     136         [ -  + ]:        673 :         if (buf2 == NULL) {
     137                 :          0 :             p = NULL;
     138                 :          0 :             nomem = 1;
     139                 :          0 :             break;
     140                 :            :         }
     141                 :        673 :         buf = buf2;
     142                 :        673 :         status = getgrgid_r(gid, &grp, buf, bufsize, &p);
     143         [ -  + ]:        673 :         if (status != 0) {
     144                 :          0 :             p = NULL;
     145                 :            :         }
     146   [ +  +  -  + ]:        673 :         if (p != NULL || status != ERANGE) {
     147                 :            :             break;
     148                 :            :         }
     149         [ #  # ]:          0 :         if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
     150                 :          0 :             nomem = 1;
     151                 :          0 :             break;
     152                 :            :         }
     153                 :          0 :         bufsize <<= 1;
     154                 :            :     }
     155                 :            : 
     156                 :        673 :     Py_END_ALLOW_THREADS
     157                 :            : #else
     158                 :            :     p = getgrgid(gid);
     159                 :            : #endif
     160         [ +  + ]:        673 :     if (p == NULL) {
     161                 :          1 :         PyMem_RawFree(buf);
     162         [ -  + ]:          1 :         if (nomem == 1) {
     163                 :            :             return PyErr_NoMemory();
     164                 :            :         }
     165                 :          1 :         PyObject *gid_obj = _PyLong_FromGid(gid);
     166         [ -  + ]:          1 :         if (gid_obj == NULL)
     167                 :          0 :             return NULL;
     168                 :          1 :         PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
     169                 :          1 :         Py_DECREF(gid_obj);
     170                 :          1 :         return NULL;
     171                 :            :     }
     172                 :        672 :     retval = mkgrent(module, p);
     173                 :            : #ifdef HAVE_GETGRGID_R
     174                 :        672 :     PyMem_RawFree(buf);
     175                 :            : #endif
     176                 :        672 :     return retval;
     177                 :            : }
     178                 :            : 
     179                 :            : /*[clinic input]
     180                 :            : grp.getgrnam
     181                 :            : 
     182                 :            :     name: unicode
     183                 :            : 
     184                 :            : Return the group database entry for the given group name.
     185                 :            : 
     186                 :            : If name is not valid, raise KeyError.
     187                 :            : [clinic start generated code]*/
     188                 :            : 
     189                 :            : static PyObject *
     190                 :        124 : grp_getgrnam_impl(PyObject *module, PyObject *name)
     191                 :            : /*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
     192                 :            : {
     193                 :        124 :     char *buf = NULL, *buf2 = NULL, *name_chars;
     194                 :        124 :     int nomem = 0;
     195                 :            :     struct group *p;
     196                 :        124 :     PyObject *bytes, *retval = NULL;
     197                 :            : 
     198         [ -  + ]:        124 :     if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
     199                 :          0 :         return NULL;
     200                 :            :     /* check for embedded null bytes */
     201         [ +  + ]:        124 :     if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
     202                 :          1 :         goto out;
     203                 :            : #ifdef HAVE_GETGRNAM_R
     204                 :            :     int status;
     205                 :            :     Py_ssize_t bufsize;
     206                 :            :     /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
     207                 :            :     struct group grp;
     208                 :            : 
     209                 :        123 :     Py_BEGIN_ALLOW_THREADS
     210                 :        123 :     bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
     211         [ -  + ]:        123 :     if (bufsize == -1) {
     212                 :          0 :         bufsize = DEFAULT_BUFFER_SIZE;
     213                 :            :     }
     214                 :            : 
     215                 :            :     while(1) {
     216                 :        123 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     217         [ -  + ]:        123 :         if (buf2 == NULL) {
     218                 :          0 :             p = NULL;
     219                 :          0 :             nomem = 1;
     220                 :          0 :             break;
     221                 :            :         }
     222                 :        123 :         buf = buf2;
     223                 :        123 :         status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
     224         [ -  + ]:        123 :         if (status != 0) {
     225                 :          0 :             p = NULL;
     226                 :            :         }
     227   [ +  +  -  + ]:        123 :         if (p != NULL || status != ERANGE) {
     228                 :            :             break;
     229                 :            :         }
     230         [ #  # ]:          0 :         if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
     231                 :          0 :             nomem = 1;
     232                 :          0 :             break;
     233                 :            :         }
     234                 :          0 :         bufsize <<= 1;
     235                 :            :     }
     236                 :            : 
     237                 :        123 :     Py_END_ALLOW_THREADS
     238                 :            : #else
     239                 :            :     p = getgrnam(name_chars);
     240                 :            : #endif
     241         [ +  + ]:        123 :     if (p == NULL) {
     242         [ -  + ]:         10 :         if (nomem == 1) {
     243                 :            :             PyErr_NoMemory();
     244                 :            :         }
     245                 :            :         else {
     246                 :         10 :             PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
     247                 :            :         }
     248                 :         10 :         goto out;
     249                 :            :     }
     250                 :        113 :     retval = mkgrent(module, p);
     251                 :        124 : out:
     252                 :        124 :     PyMem_RawFree(buf);
     253                 :        124 :     Py_DECREF(bytes);
     254                 :        124 :     return retval;
     255                 :            : }
     256                 :            : 
     257                 :            : /*[clinic input]
     258                 :            : grp.getgrall
     259                 :            : 
     260                 :            : Return a list of all available group entries, in arbitrary order.
     261                 :            : 
     262                 :            : An entry whose name starts with '+' or '-' represents an instruction
     263                 :            : to use YP/NIS and may not be accessible via getgrnam or getgrgid.
     264                 :            : [clinic start generated code]*/
     265                 :            : 
     266                 :            : static PyObject *
     267                 :          4 : grp_getgrall_impl(PyObject *module)
     268                 :            : /*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
     269                 :            : {
     270                 :            :     PyObject *d;
     271                 :            :     struct group *p;
     272                 :            : 
     273         [ -  + ]:          4 :     if ((d = PyList_New(0)) == NULL)
     274                 :          0 :         return NULL;
     275                 :          4 :     setgrent();
     276         [ +  + ]:        404 :     while ((p = getgrent()) != NULL) {
     277                 :        400 :         PyObject *v = mkgrent(module, p);
     278   [ +  -  -  + ]:        400 :         if (v == NULL || PyList_Append(d, v) != 0) {
     279                 :          0 :             Py_XDECREF(v);
     280                 :          0 :             Py_DECREF(d);
     281                 :          0 :             endgrent();
     282                 :          0 :             return NULL;
     283                 :            :         }
     284                 :        400 :         Py_DECREF(v);
     285                 :            :     }
     286                 :          4 :     endgrent();
     287                 :          4 :     return d;
     288                 :            : }
     289                 :            : 
     290                 :            : static PyMethodDef grp_methods[] = {
     291                 :            :     GRP_GETGRGID_METHODDEF
     292                 :            :     GRP_GETGRNAM_METHODDEF
     293                 :            :     GRP_GETGRALL_METHODDEF
     294                 :            :     {NULL, NULL}
     295                 :            : };
     296                 :            : 
     297                 :            : PyDoc_STRVAR(grp__doc__,
     298                 :            : "Access to the Unix group database.\n\
     299                 :            : \n\
     300                 :            : Group entries are reported as 4-tuples containing the following fields\n\
     301                 :            : from the group database, in order:\n\
     302                 :            : \n\
     303                 :            :   gr_name   - name of the group\n\
     304                 :            :   gr_passwd - group password (encrypted); often empty\n\
     305                 :            :   gr_gid    - numeric ID of the group\n\
     306                 :            :   gr_mem    - list of members\n\
     307                 :            : \n\
     308                 :            : The gid is an integer, name and password are strings.  (Note that most\n\
     309                 :            : users are not explicitly listed as members of the groups they are in\n\
     310                 :            : according to the password database.  Check both databases to get\n\
     311                 :            : complete membership information.)");
     312                 :            : 
     313                 :            : static int
     314                 :         82 : grpmodule_exec(PyObject *module)
     315                 :            : {
     316                 :         82 :     grpmodulestate *state = get_grp_state(module);
     317                 :            : 
     318                 :         82 :     state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc);
     319         [ -  + ]:         82 :     if (state->StructGrpType == NULL) {
     320                 :          0 :         return -1;
     321                 :            :     }
     322         [ -  + ]:         82 :     if (PyModule_AddType(module, state->StructGrpType) < 0) {
     323                 :          0 :         return -1;
     324                 :            :     }
     325                 :         82 :     return 0;
     326                 :            : }
     327                 :            : 
     328                 :            : static PyModuleDef_Slot grpmodule_slots[] = {
     329                 :            :     {Py_mod_exec, grpmodule_exec},
     330                 :            :     {0, NULL}
     331                 :            : };
     332                 :            : 
     333                 :        814 : static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
     334   [ +  -  -  + ]:        814 :     Py_VISIT(get_grp_state(m)->StructGrpType);
     335                 :        814 :     return 0;
     336                 :            : }
     337                 :            : 
     338                 :        158 : static int grpmodule_clear(PyObject *m) {
     339         [ +  + ]:        158 :     Py_CLEAR(get_grp_state(m)->StructGrpType);
     340                 :        158 :     return 0;
     341                 :            : }
     342                 :            : 
     343                 :         82 : static void grpmodule_free(void *m) {
     344                 :         82 :     grpmodule_clear((PyObject *)m);
     345                 :         82 : }
     346                 :            : 
     347                 :            : static struct PyModuleDef grpmodule = {
     348                 :            :     PyModuleDef_HEAD_INIT,
     349                 :            :     .m_name = "grp",
     350                 :            :     .m_doc = grp__doc__,
     351                 :            :     .m_size = sizeof(grpmodulestate),
     352                 :            :     .m_methods = grp_methods,
     353                 :            :     .m_slots = grpmodule_slots,
     354                 :            :     .m_traverse = grpmodule_traverse,
     355                 :            :     .m_clear = grpmodule_clear,
     356                 :            :     .m_free = grpmodule_free,
     357                 :            : };
     358                 :            : 
     359                 :            : PyMODINIT_FUNC
     360                 :         82 : PyInit_grp(void)
     361                 :            : {
     362                 :         82 :    return PyModuleDef_Init(&grpmodule);
     363                 :            : }

Generated by: LCOV version 1.14