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 : : }
|