• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*
get_grp_state(PyObject * module)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 *
mkgrent(PyObject * module,struct group * p)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 != NULL; member++) {
69         PyObject *x = PyUnicode_DecodeFSDefault(*member);
70         if (x == NULL || PyList_Append(w, x) != 0) {
71             Py_XDECREF(x);
72             Py_DECREF(w);
73             Py_DECREF(v);
74             return NULL;
75         }
76         Py_DECREF(x);
77     }
78 
79 #define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
80     SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
81     if (p->gr_passwd)
82             SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
83     else {
84             SET(setIndex++, Py_None);
85             Py_INCREF(Py_None);
86     }
87     SET(setIndex++, _PyLong_FromGid(p->gr_gid));
88     SET(setIndex++, w);
89 #undef SET
90 
91     if (PyErr_Occurred()) {
92         Py_DECREF(v);
93         return NULL;
94     }
95 
96     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 *
grp_getgrgid_impl(PyObject * module,PyObject * id)110 grp_getgrgid_impl(PyObject *module, PyObject *id)
111 /*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
112 {
113     PyObject *retval = NULL;
114     int nomem = 0;
115     char *buf = NULL, *buf2 = NULL;
116     gid_t gid;
117     struct group *p;
118 
119     if (!_Py_Gid_Converter(id, &gid)) {
120         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     Py_BEGIN_ALLOW_THREADS
129     bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
130     if (bufsize == -1) {
131         bufsize = DEFAULT_BUFFER_SIZE;
132     }
133 
134     while (1) {
135         buf2 = PyMem_RawRealloc(buf, bufsize);
136         if (buf2 == NULL) {
137             p = NULL;
138             nomem = 1;
139             break;
140         }
141         buf = buf2;
142         status = getgrgid_r(gid, &grp, buf, bufsize, &p);
143         if (status != 0) {
144             p = NULL;
145         }
146         if (p != NULL || status != ERANGE) {
147             break;
148         }
149         if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
150             nomem = 1;
151             break;
152         }
153         bufsize <<= 1;
154     }
155 
156     Py_END_ALLOW_THREADS
157 #else
158     p = getgrgid(gid);
159 #endif
160     if (p == NULL) {
161         PyMem_RawFree(buf);
162         if (nomem == 1) {
163             return PyErr_NoMemory();
164         }
165         PyObject *gid_obj = _PyLong_FromGid(gid);
166         if (gid_obj == NULL)
167             return NULL;
168         PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
169         Py_DECREF(gid_obj);
170         return NULL;
171     }
172     retval = mkgrent(module, p);
173 #ifdef HAVE_GETGRGID_R
174     PyMem_RawFree(buf);
175 #endif
176     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 *
grp_getgrnam_impl(PyObject * module,PyObject * name)190 grp_getgrnam_impl(PyObject *module, PyObject *name)
191 /*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
192 {
193     char *buf = NULL, *buf2 = NULL, *name_chars;
194     int nomem = 0;
195     struct group *p;
196     PyObject *bytes, *retval = NULL;
197 
198     if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
199         return NULL;
200     /* check for embedded null bytes */
201     if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
202         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     Py_BEGIN_ALLOW_THREADS
210     bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
211     if (bufsize == -1) {
212         bufsize = DEFAULT_BUFFER_SIZE;
213     }
214 
215     while(1) {
216         buf2 = PyMem_RawRealloc(buf, bufsize);
217         if (buf2 == NULL) {
218             p = NULL;
219             nomem = 1;
220             break;
221         }
222         buf = buf2;
223         status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
224         if (status != 0) {
225             p = NULL;
226         }
227         if (p != NULL || status != ERANGE) {
228             break;
229         }
230         if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
231             nomem = 1;
232             break;
233         }
234         bufsize <<= 1;
235     }
236 
237     Py_END_ALLOW_THREADS
238 #else
239     p = getgrnam(name_chars);
240 #endif
241     if (p == NULL) {
242         if (nomem == 1) {
243             PyErr_NoMemory();
244         }
245         else {
246             PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
247         }
248         goto out;
249     }
250     retval = mkgrent(module, p);
251 out:
252     PyMem_RawFree(buf);
253     Py_DECREF(bytes);
254     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 *
grp_getgrall_impl(PyObject * module)267 grp_getgrall_impl(PyObject *module)
268 /*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
269 {
270     PyObject *d;
271     struct group *p;
272 
273     if ((d = PyList_New(0)) == NULL)
274         return NULL;
275     setgrent();
276     while ((p = getgrent()) != NULL) {
277         PyObject *v = mkgrent(module, p);
278         if (v == NULL || PyList_Append(d, v) != 0) {
279             Py_XDECREF(v);
280             Py_DECREF(d);
281             endgrent();
282             return NULL;
283         }
284         Py_DECREF(v);
285     }
286     endgrent();
287     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
grpmodule_exec(PyObject * module)314 grpmodule_exec(PyObject *module)
315 {
316     grpmodulestate *state = get_grp_state(module);
317 
318     state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc);
319     if (state->StructGrpType == NULL) {
320         return -1;
321     }
322     if (PyModule_AddType(module, state->StructGrpType) < 0) {
323         return -1;
324     }
325     return 0;
326 }
327 
328 static PyModuleDef_Slot grpmodule_slots[] = {
329     {Py_mod_exec, grpmodule_exec},
330     {0, NULL}
331 };
332 
grpmodule_traverse(PyObject * m,visitproc visit,void * arg)333 static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
334     Py_VISIT(get_grp_state(m)->StructGrpType);
335     return 0;
336 }
337 
grpmodule_clear(PyObject * m)338 static int grpmodule_clear(PyObject *m) {
339     Py_CLEAR(get_grp_state(m)->StructGrpType);
340     return 0;
341 }
342 
grpmodule_free(void * m)343 static void grpmodule_free(void *m) {
344     grpmodule_clear((PyObject *)m);
345 }
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
PyInit_grp(void)360 PyInit_grp(void)
361 {
362    return PyModuleDef_Init(&grpmodule);
363 }
364