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