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