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 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
337 {0, NULL}
338 };
339
340 static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
341 Py_VISIT(get_grp_state(m)->StructGrpType);
342 return 0;
343 }
344
345 static int grpmodule_clear(PyObject *m) {
346 Py_CLEAR(get_grp_state(m)->StructGrpType);
347 return 0;
348 }
349
350 static void grpmodule_free(void *m) {
351 grpmodule_clear((PyObject *)m);
352 }
353
354 static struct PyModuleDef grpmodule = {
355 PyModuleDef_HEAD_INIT,
356 .m_name = "grp",
357 .m_doc = grp__doc__,
358 .m_size = sizeof(grpmodulestate),
359 .m_methods = grp_methods,
360 .m_slots = grpmodule_slots,
361 .m_traverse = grpmodule_traverse,
362 .m_clear = grpmodule_clear,
363 .m_free = grpmodule_free,
364 };
365
366 PyMODINIT_FUNC
367 PyInit_grp(void)
368 {
369 return PyModuleDef_Init(&grpmodule);
370 }