LCOV - code coverage report
Current view: top level - Modules - grpmodule.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 99 139 71.2 %
Date: 2022-07-07 18:19:46 Functions: 10 10 100.0 %

          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        3083 : get_grp_state(PyObject *module)
      43             : {
      44        3083 :     void *state = PyModule_GetState(module);
      45        3083 :     assert(state != NULL);
      46        3083 :     return (grpmodulestate *)state;
      47             : }
      48             : 
      49             : static struct PyModuleDef grpmodule;
      50             : 
      51             : #define DEFAULT_BUFFER_SIZE 1024
      52             : 
      53             : static PyObject *
      54         993 : mkgrent(PyObject *module, struct group *p)
      55             : {
      56         993 :     int setIndex = 0;
      57             :     PyObject *v, *w;
      58             :     char **member;
      59             : 
      60         993 :     v = PyStructSequence_New(get_grp_state(module)->StructGrpType);
      61         993 :     if (v == NULL)
      62           0 :         return NULL;
      63             : 
      64         993 :     if ((w = PyList_New(0)) == NULL) {
      65           0 :         Py_DECREF(v);
      66           0 :         return NULL;
      67             :     }
      68        1095 :     for (member = p->gr_mem; *member != NULL; member++) {
      69         102 :         PyObject *x = PyUnicode_DecodeFSDefault(*member);
      70         102 :         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         102 :         Py_DECREF(x);
      77             :     }
      78             : 
      79             : #define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
      80         993 :     SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
      81         993 :     if (p->gr_passwd)
      82         993 :             SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
      83             :     else {
      84           0 :             SET(setIndex++, Py_None);
      85           0 :             Py_INCREF(Py_None);
      86             :     }
      87         993 :     SET(setIndex++, _PyLong_FromGid(p->gr_gid));
      88         993 :     SET(setIndex++, w);
      89             : #undef SET
      90             : 
      91         993 :     if (PyErr_Occurred()) {
      92           0 :         Py_DECREF(v);
      93           0 :         return NULL;
      94             :     }
      95             : 
      96         993 :     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         643 : grp_getgrgid_impl(PyObject *module, PyObject *id)
     111             : /*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
     112             : {
     113         643 :     PyObject *retval = NULL;
     114         643 :     int nomem = 0;
     115         643 :     char *buf = NULL, *buf2 = NULL;
     116             :     gid_t gid;
     117             :     struct group *p;
     118             : 
     119         643 :     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         641 :     Py_BEGIN_ALLOW_THREADS
     129         641 :     bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
     130         641 :     if (bufsize == -1) {
     131           0 :         bufsize = DEFAULT_BUFFER_SIZE;
     132             :     }
     133             : 
     134             :     while (1) {
     135         641 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     136         641 :         if (buf2 == NULL) {
     137           0 :             p = NULL;
     138           0 :             nomem = 1;
     139           0 :             break;
     140             :         }
     141         641 :         buf = buf2;
     142         641 :         status = getgrgid_r(gid, &grp, buf, bufsize, &p);
     143         641 :         if (status != 0) {
     144           0 :             p = NULL;
     145             :         }
     146         641 :         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         641 :     Py_END_ALLOW_THREADS
     157             : #else
     158             :     p = getgrgid(gid);
     159             : #endif
     160         641 :     if (p == NULL) {
     161           1 :         PyMem_RawFree(buf);
     162           1 :         if (nomem == 1) {
     163           0 :             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         640 :     retval = mkgrent(module, p);
     173             : #ifdef HAVE_GETGRGID_R
     174         640 :     PyMem_RawFree(buf);
     175             : #endif
     176         640 :     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          86 : grp_getgrnam_impl(PyObject *module, PyObject *name)
     191             : /*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
     192             : {
     193          86 :     char *buf = NULL, *buf2 = NULL, *name_chars;
     194          86 :     int nomem = 0;
     195             :     struct group *p;
     196          86 :     PyObject *bytes, *retval = NULL;
     197             : 
     198          86 :     if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
     199           0 :         return NULL;
     200             :     /* check for embedded null bytes */
     201          86 :     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          85 :     Py_BEGIN_ALLOW_THREADS
     210          85 :     bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
     211          85 :     if (bufsize == -1) {
     212           0 :         bufsize = DEFAULT_BUFFER_SIZE;
     213             :     }
     214             : 
     215             :     while(1) {
     216          85 :         buf2 = PyMem_RawRealloc(buf, bufsize);
     217          85 :         if (buf2 == NULL) {
     218           0 :             p = NULL;
     219           0 :             nomem = 1;
     220           0 :             break;
     221             :         }
     222          85 :         buf = buf2;
     223          85 :         status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
     224          85 :         if (status != 0) {
     225           0 :             p = NULL;
     226             :         }
     227          85 :         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          85 :     Py_END_ALLOW_THREADS
     238             : #else
     239             :     p = getgrnam(name_chars);
     240             : #endif
     241          85 :     if (p == NULL) {
     242           4 :         if (nomem == 1) {
     243           0 :             PyErr_NoMemory();
     244             :         }
     245             :         else {
     246           4 :             PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
     247             :         }
     248           4 :         goto out;
     249             :     }
     250          81 :     retval = mkgrent(module, p);
     251          86 : out:
     252          86 :     PyMem_RawFree(buf);
     253          86 :     Py_DECREF(bytes);
     254          86 :     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         276 :     while ((p = getgrent()) != NULL) {
     277         272 :         PyObject *v = mkgrent(module, p);
     278         272 :         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         272 :         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          81 : grpmodule_exec(PyObject *module)
     315             : {
     316          81 :     grpmodulestate *state = get_grp_state(module);
     317             : 
     318          81 :     state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc);
     319          81 :     if (state->StructGrpType == NULL) {
     320           0 :         return -1;
     321             :     }
     322          81 :     if (PyModule_AddType(module, state->StructGrpType) < 0) {
     323           0 :         return -1;
     324             :     }
     325          81 :     return 0;
     326             : }
     327             : 
     328             : static PyModuleDef_Slot grpmodule_slots[] = {
     329             :     {Py_mod_exec, grpmodule_exec},
     330             :     {0, NULL}
     331             : };
     332             : 
     333         886 : static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
     334         886 :     Py_VISIT(get_grp_state(m)->StructGrpType);
     335         886 :     return 0;
     336             : }
     337             : 
     338         156 : static int grpmodule_clear(PyObject *m) {
     339         156 :     Py_CLEAR(get_grp_state(m)->StructGrpType);
     340         156 :     return 0;
     341             : }
     342             : 
     343          81 : static void grpmodule_free(void *m) {
     344          81 :     grpmodule_clear((PyObject *)m);
     345          81 : }
     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          81 : PyInit_grp(void)
     361             : {
     362          81 :    return PyModuleDef_Init(&grpmodule);
     363             : }

Generated by: LCOV version 1.14