17db96d56Sopenharmony_ci
27db96d56Sopenharmony_ci/* UNIX group file access module */
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ci#include "Python.h"
57db96d56Sopenharmony_ci#include "posixmodule.h"
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci#include <grp.h>
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci#include "clinic/grpmodule.c.h"
107db96d56Sopenharmony_ci/*[clinic input]
117db96d56Sopenharmony_cimodule grp
127db96d56Sopenharmony_ci[clinic start generated code]*/
137db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cade63f2ed1bd9f8]*/
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_cistatic PyStructSequence_Field struct_group_type_fields[] = {
167db96d56Sopenharmony_ci   {"gr_name", "group name"},
177db96d56Sopenharmony_ci   {"gr_passwd", "password"},
187db96d56Sopenharmony_ci   {"gr_gid", "group id"},
197db96d56Sopenharmony_ci   {"gr_mem", "group members"},
207db96d56Sopenharmony_ci   {0}
217db96d56Sopenharmony_ci};
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ciPyDoc_STRVAR(struct_group__doc__,
247db96d56Sopenharmony_ci"grp.struct_group: Results from getgr*() routines.\n\n\
257db96d56Sopenharmony_ciThis object may be accessed either as a tuple of\n\
267db96d56Sopenharmony_ci  (gr_name,gr_passwd,gr_gid,gr_mem)\n\
277db96d56Sopenharmony_cior via the object attributes as named in the above tuple.\n");
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_cistatic PyStructSequence_Desc struct_group_type_desc = {
307db96d56Sopenharmony_ci   "grp.struct_group",
317db96d56Sopenharmony_ci   struct_group__doc__,
327db96d56Sopenharmony_ci   struct_group_type_fields,
337db96d56Sopenharmony_ci   4,
347db96d56Sopenharmony_ci};
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_citypedef struct {
387db96d56Sopenharmony_ci  PyTypeObject *StructGrpType;
397db96d56Sopenharmony_ci} grpmodulestate;
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_cistatic inline grpmodulestate*
427db96d56Sopenharmony_ciget_grp_state(PyObject *module)
437db96d56Sopenharmony_ci{
447db96d56Sopenharmony_ci    void *state = PyModule_GetState(module);
457db96d56Sopenharmony_ci    assert(state != NULL);
467db96d56Sopenharmony_ci    return (grpmodulestate *)state;
477db96d56Sopenharmony_ci}
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_cistatic struct PyModuleDef grpmodule;
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci#define DEFAULT_BUFFER_SIZE 1024
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_cistatic PyObject *
547db96d56Sopenharmony_cimkgrent(PyObject *module, struct group *p)
557db96d56Sopenharmony_ci{
567db96d56Sopenharmony_ci    int setIndex = 0;
577db96d56Sopenharmony_ci    PyObject *v, *w;
587db96d56Sopenharmony_ci    char **member;
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci    v = PyStructSequence_New(get_grp_state(module)->StructGrpType);
617db96d56Sopenharmony_ci    if (v == NULL)
627db96d56Sopenharmony_ci        return NULL;
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci    if ((w = PyList_New(0)) == NULL) {
657db96d56Sopenharmony_ci        Py_DECREF(v);
667db96d56Sopenharmony_ci        return NULL;
677db96d56Sopenharmony_ci    }
687db96d56Sopenharmony_ci    for (member = p->gr_mem; *member != NULL; member++) {
697db96d56Sopenharmony_ci        PyObject *x = PyUnicode_DecodeFSDefault(*member);
707db96d56Sopenharmony_ci        if (x == NULL || PyList_Append(w, x) != 0) {
717db96d56Sopenharmony_ci            Py_XDECREF(x);
727db96d56Sopenharmony_ci            Py_DECREF(w);
737db96d56Sopenharmony_ci            Py_DECREF(v);
747db96d56Sopenharmony_ci            return NULL;
757db96d56Sopenharmony_ci        }
767db96d56Sopenharmony_ci        Py_DECREF(x);
777db96d56Sopenharmony_ci    }
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
807db96d56Sopenharmony_ci    SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
817db96d56Sopenharmony_ci    if (p->gr_passwd)
827db96d56Sopenharmony_ci            SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
837db96d56Sopenharmony_ci    else {
847db96d56Sopenharmony_ci            SET(setIndex++, Py_None);
857db96d56Sopenharmony_ci            Py_INCREF(Py_None);
867db96d56Sopenharmony_ci    }
877db96d56Sopenharmony_ci    SET(setIndex++, _PyLong_FromGid(p->gr_gid));
887db96d56Sopenharmony_ci    SET(setIndex++, w);
897db96d56Sopenharmony_ci#undef SET
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci    if (PyErr_Occurred()) {
927db96d56Sopenharmony_ci        Py_DECREF(v);
937db96d56Sopenharmony_ci        return NULL;
947db96d56Sopenharmony_ci    }
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci    return v;
977db96d56Sopenharmony_ci}
987db96d56Sopenharmony_ci
997db96d56Sopenharmony_ci/*[clinic input]
1007db96d56Sopenharmony_cigrp.getgrgid
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci    id: object
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ciReturn the group database entry for the given numeric group ID.
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ciIf id is not valid, raise KeyError.
1077db96d56Sopenharmony_ci[clinic start generated code]*/
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_cistatic PyObject *
1107db96d56Sopenharmony_cigrp_getgrgid_impl(PyObject *module, PyObject *id)
1117db96d56Sopenharmony_ci/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
1127db96d56Sopenharmony_ci{
1137db96d56Sopenharmony_ci    PyObject *retval = NULL;
1147db96d56Sopenharmony_ci    int nomem = 0;
1157db96d56Sopenharmony_ci    char *buf = NULL, *buf2 = NULL;
1167db96d56Sopenharmony_ci    gid_t gid;
1177db96d56Sopenharmony_ci    struct group *p;
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_ci    if (!_Py_Gid_Converter(id, &gid)) {
1207db96d56Sopenharmony_ci        return NULL;
1217db96d56Sopenharmony_ci    }
1227db96d56Sopenharmony_ci#ifdef HAVE_GETGRGID_R
1237db96d56Sopenharmony_ci    int status;
1247db96d56Sopenharmony_ci    Py_ssize_t bufsize;
1257db96d56Sopenharmony_ci    /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
1267db96d56Sopenharmony_ci    struct group grp;
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci    Py_BEGIN_ALLOW_THREADS
1297db96d56Sopenharmony_ci    bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
1307db96d56Sopenharmony_ci    if (bufsize == -1) {
1317db96d56Sopenharmony_ci        bufsize = DEFAULT_BUFFER_SIZE;
1327db96d56Sopenharmony_ci    }
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_ci    while (1) {
1357db96d56Sopenharmony_ci        buf2 = PyMem_RawRealloc(buf, bufsize);
1367db96d56Sopenharmony_ci        if (buf2 == NULL) {
1377db96d56Sopenharmony_ci            p = NULL;
1387db96d56Sopenharmony_ci            nomem = 1;
1397db96d56Sopenharmony_ci            break;
1407db96d56Sopenharmony_ci        }
1417db96d56Sopenharmony_ci        buf = buf2;
1427db96d56Sopenharmony_ci        status = getgrgid_r(gid, &grp, buf, bufsize, &p);
1437db96d56Sopenharmony_ci        if (status != 0) {
1447db96d56Sopenharmony_ci            p = NULL;
1457db96d56Sopenharmony_ci        }
1467db96d56Sopenharmony_ci        if (p != NULL || status != ERANGE) {
1477db96d56Sopenharmony_ci            break;
1487db96d56Sopenharmony_ci        }
1497db96d56Sopenharmony_ci        if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
1507db96d56Sopenharmony_ci            nomem = 1;
1517db96d56Sopenharmony_ci            break;
1527db96d56Sopenharmony_ci        }
1537db96d56Sopenharmony_ci        bufsize <<= 1;
1547db96d56Sopenharmony_ci    }
1557db96d56Sopenharmony_ci
1567db96d56Sopenharmony_ci    Py_END_ALLOW_THREADS
1577db96d56Sopenharmony_ci#else
1587db96d56Sopenharmony_ci    p = getgrgid(gid);
1597db96d56Sopenharmony_ci#endif
1607db96d56Sopenharmony_ci    if (p == NULL) {
1617db96d56Sopenharmony_ci        PyMem_RawFree(buf);
1627db96d56Sopenharmony_ci        if (nomem == 1) {
1637db96d56Sopenharmony_ci            return PyErr_NoMemory();
1647db96d56Sopenharmony_ci        }
1657db96d56Sopenharmony_ci        PyObject *gid_obj = _PyLong_FromGid(gid);
1667db96d56Sopenharmony_ci        if (gid_obj == NULL)
1677db96d56Sopenharmony_ci            return NULL;
1687db96d56Sopenharmony_ci        PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
1697db96d56Sopenharmony_ci        Py_DECREF(gid_obj);
1707db96d56Sopenharmony_ci        return NULL;
1717db96d56Sopenharmony_ci    }
1727db96d56Sopenharmony_ci    retval = mkgrent(module, p);
1737db96d56Sopenharmony_ci#ifdef HAVE_GETGRGID_R
1747db96d56Sopenharmony_ci    PyMem_RawFree(buf);
1757db96d56Sopenharmony_ci#endif
1767db96d56Sopenharmony_ci    return retval;
1777db96d56Sopenharmony_ci}
1787db96d56Sopenharmony_ci
1797db96d56Sopenharmony_ci/*[clinic input]
1807db96d56Sopenharmony_cigrp.getgrnam
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ci    name: unicode
1837db96d56Sopenharmony_ci
1847db96d56Sopenharmony_ciReturn the group database entry for the given group name.
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ciIf name is not valid, raise KeyError.
1877db96d56Sopenharmony_ci[clinic start generated code]*/
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_cistatic PyObject *
1907db96d56Sopenharmony_cigrp_getgrnam_impl(PyObject *module, PyObject *name)
1917db96d56Sopenharmony_ci/*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
1927db96d56Sopenharmony_ci{
1937db96d56Sopenharmony_ci    char *buf = NULL, *buf2 = NULL, *name_chars;
1947db96d56Sopenharmony_ci    int nomem = 0;
1957db96d56Sopenharmony_ci    struct group *p;
1967db96d56Sopenharmony_ci    PyObject *bytes, *retval = NULL;
1977db96d56Sopenharmony_ci
1987db96d56Sopenharmony_ci    if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
1997db96d56Sopenharmony_ci        return NULL;
2007db96d56Sopenharmony_ci    /* check for embedded null bytes */
2017db96d56Sopenharmony_ci    if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
2027db96d56Sopenharmony_ci        goto out;
2037db96d56Sopenharmony_ci#ifdef HAVE_GETGRNAM_R
2047db96d56Sopenharmony_ci    int status;
2057db96d56Sopenharmony_ci    Py_ssize_t bufsize;
2067db96d56Sopenharmony_ci    /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
2077db96d56Sopenharmony_ci    struct group grp;
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci    Py_BEGIN_ALLOW_THREADS
2107db96d56Sopenharmony_ci    bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
2117db96d56Sopenharmony_ci    if (bufsize == -1) {
2127db96d56Sopenharmony_ci        bufsize = DEFAULT_BUFFER_SIZE;
2137db96d56Sopenharmony_ci    }
2147db96d56Sopenharmony_ci
2157db96d56Sopenharmony_ci    while(1) {
2167db96d56Sopenharmony_ci        buf2 = PyMem_RawRealloc(buf, bufsize);
2177db96d56Sopenharmony_ci        if (buf2 == NULL) {
2187db96d56Sopenharmony_ci            p = NULL;
2197db96d56Sopenharmony_ci            nomem = 1;
2207db96d56Sopenharmony_ci            break;
2217db96d56Sopenharmony_ci        }
2227db96d56Sopenharmony_ci        buf = buf2;
2237db96d56Sopenharmony_ci        status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
2247db96d56Sopenharmony_ci        if (status != 0) {
2257db96d56Sopenharmony_ci            p = NULL;
2267db96d56Sopenharmony_ci        }
2277db96d56Sopenharmony_ci        if (p != NULL || status != ERANGE) {
2287db96d56Sopenharmony_ci            break;
2297db96d56Sopenharmony_ci        }
2307db96d56Sopenharmony_ci        if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
2317db96d56Sopenharmony_ci            nomem = 1;
2327db96d56Sopenharmony_ci            break;
2337db96d56Sopenharmony_ci        }
2347db96d56Sopenharmony_ci        bufsize <<= 1;
2357db96d56Sopenharmony_ci    }
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ci    Py_END_ALLOW_THREADS
2387db96d56Sopenharmony_ci#else
2397db96d56Sopenharmony_ci    p = getgrnam(name_chars);
2407db96d56Sopenharmony_ci#endif
2417db96d56Sopenharmony_ci    if (p == NULL) {
2427db96d56Sopenharmony_ci        if (nomem == 1) {
2437db96d56Sopenharmony_ci            PyErr_NoMemory();
2447db96d56Sopenharmony_ci        }
2457db96d56Sopenharmony_ci        else {
2467db96d56Sopenharmony_ci            PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
2477db96d56Sopenharmony_ci        }
2487db96d56Sopenharmony_ci        goto out;
2497db96d56Sopenharmony_ci    }
2507db96d56Sopenharmony_ci    retval = mkgrent(module, p);
2517db96d56Sopenharmony_ciout:
2527db96d56Sopenharmony_ci    PyMem_RawFree(buf);
2537db96d56Sopenharmony_ci    Py_DECREF(bytes);
2547db96d56Sopenharmony_ci    return retval;
2557db96d56Sopenharmony_ci}
2567db96d56Sopenharmony_ci
2577db96d56Sopenharmony_ci/*[clinic input]
2587db96d56Sopenharmony_cigrp.getgrall
2597db96d56Sopenharmony_ci
2607db96d56Sopenharmony_ciReturn a list of all available group entries, in arbitrary order.
2617db96d56Sopenharmony_ci
2627db96d56Sopenharmony_ciAn entry whose name starts with '+' or '-' represents an instruction
2637db96d56Sopenharmony_cito use YP/NIS and may not be accessible via getgrnam or getgrgid.
2647db96d56Sopenharmony_ci[clinic start generated code]*/
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_cistatic PyObject *
2677db96d56Sopenharmony_cigrp_getgrall_impl(PyObject *module)
2687db96d56Sopenharmony_ci/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
2697db96d56Sopenharmony_ci{
2707db96d56Sopenharmony_ci    PyObject *d;
2717db96d56Sopenharmony_ci    struct group *p;
2727db96d56Sopenharmony_ci
2737db96d56Sopenharmony_ci    if ((d = PyList_New(0)) == NULL)
2747db96d56Sopenharmony_ci        return NULL;
2757db96d56Sopenharmony_ci    setgrent();
2767db96d56Sopenharmony_ci    while ((p = getgrent()) != NULL) {
2777db96d56Sopenharmony_ci        PyObject *v = mkgrent(module, p);
2787db96d56Sopenharmony_ci        if (v == NULL || PyList_Append(d, v) != 0) {
2797db96d56Sopenharmony_ci            Py_XDECREF(v);
2807db96d56Sopenharmony_ci            Py_DECREF(d);
2817db96d56Sopenharmony_ci            endgrent();
2827db96d56Sopenharmony_ci            return NULL;
2837db96d56Sopenharmony_ci        }
2847db96d56Sopenharmony_ci        Py_DECREF(v);
2857db96d56Sopenharmony_ci    }
2867db96d56Sopenharmony_ci    endgrent();
2877db96d56Sopenharmony_ci    return d;
2887db96d56Sopenharmony_ci}
2897db96d56Sopenharmony_ci
2907db96d56Sopenharmony_cistatic PyMethodDef grp_methods[] = {
2917db96d56Sopenharmony_ci    GRP_GETGRGID_METHODDEF
2927db96d56Sopenharmony_ci    GRP_GETGRNAM_METHODDEF
2937db96d56Sopenharmony_ci    GRP_GETGRALL_METHODDEF
2947db96d56Sopenharmony_ci    {NULL, NULL}
2957db96d56Sopenharmony_ci};
2967db96d56Sopenharmony_ci
2977db96d56Sopenharmony_ciPyDoc_STRVAR(grp__doc__,
2987db96d56Sopenharmony_ci"Access to the Unix group database.\n\
2997db96d56Sopenharmony_ci\n\
3007db96d56Sopenharmony_ciGroup entries are reported as 4-tuples containing the following fields\n\
3017db96d56Sopenharmony_cifrom the group database, in order:\n\
3027db96d56Sopenharmony_ci\n\
3037db96d56Sopenharmony_ci  gr_name   - name of the group\n\
3047db96d56Sopenharmony_ci  gr_passwd - group password (encrypted); often empty\n\
3057db96d56Sopenharmony_ci  gr_gid    - numeric ID of the group\n\
3067db96d56Sopenharmony_ci  gr_mem    - list of members\n\
3077db96d56Sopenharmony_ci\n\
3087db96d56Sopenharmony_ciThe gid is an integer, name and password are strings.  (Note that most\n\
3097db96d56Sopenharmony_ciusers are not explicitly listed as members of the groups they are in\n\
3107db96d56Sopenharmony_ciaccording to the password database.  Check both databases to get\n\
3117db96d56Sopenharmony_cicomplete membership information.)");
3127db96d56Sopenharmony_ci
3137db96d56Sopenharmony_cistatic int
3147db96d56Sopenharmony_cigrpmodule_exec(PyObject *module)
3157db96d56Sopenharmony_ci{
3167db96d56Sopenharmony_ci    grpmodulestate *state = get_grp_state(module);
3177db96d56Sopenharmony_ci
3187db96d56Sopenharmony_ci    state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc);
3197db96d56Sopenharmony_ci    if (state->StructGrpType == NULL) {
3207db96d56Sopenharmony_ci        return -1;
3217db96d56Sopenharmony_ci    }
3227db96d56Sopenharmony_ci    if (PyModule_AddType(module, state->StructGrpType) < 0) {
3237db96d56Sopenharmony_ci        return -1;
3247db96d56Sopenharmony_ci    }
3257db96d56Sopenharmony_ci    return 0;
3267db96d56Sopenharmony_ci}
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_cistatic PyModuleDef_Slot grpmodule_slots[] = {
3297db96d56Sopenharmony_ci    {Py_mod_exec, grpmodule_exec},
3307db96d56Sopenharmony_ci    {0, NULL}
3317db96d56Sopenharmony_ci};
3327db96d56Sopenharmony_ci
3337db96d56Sopenharmony_cistatic int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
3347db96d56Sopenharmony_ci    Py_VISIT(get_grp_state(m)->StructGrpType);
3357db96d56Sopenharmony_ci    return 0;
3367db96d56Sopenharmony_ci}
3377db96d56Sopenharmony_ci
3387db96d56Sopenharmony_cistatic int grpmodule_clear(PyObject *m) {
3397db96d56Sopenharmony_ci    Py_CLEAR(get_grp_state(m)->StructGrpType);
3407db96d56Sopenharmony_ci    return 0;
3417db96d56Sopenharmony_ci}
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_cistatic void grpmodule_free(void *m) {
3447db96d56Sopenharmony_ci    grpmodule_clear((PyObject *)m);
3457db96d56Sopenharmony_ci}
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_cistatic struct PyModuleDef grpmodule = {
3487db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
3497db96d56Sopenharmony_ci    .m_name = "grp",
3507db96d56Sopenharmony_ci    .m_doc = grp__doc__,
3517db96d56Sopenharmony_ci    .m_size = sizeof(grpmodulestate),
3527db96d56Sopenharmony_ci    .m_methods = grp_methods,
3537db96d56Sopenharmony_ci    .m_slots = grpmodule_slots,
3547db96d56Sopenharmony_ci    .m_traverse = grpmodule_traverse,
3557db96d56Sopenharmony_ci    .m_clear = grpmodule_clear,
3567db96d56Sopenharmony_ci    .m_free = grpmodule_free,
3577db96d56Sopenharmony_ci};
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ciPyMODINIT_FUNC
3607db96d56Sopenharmony_ciPyInit_grp(void)
3617db96d56Sopenharmony_ci{
3627db96d56Sopenharmony_ci   return PyModuleDef_Init(&grpmodule);
3637db96d56Sopenharmony_ci}
364