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