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 static int initialized;
38 static PyTypeObject StructGrpType;
39
40 #define DEFAULT_BUFFER_SIZE 1024
41
42 static PyObject *
mkgrent(struct group * p)43 mkgrent(struct group *p)
44 {
45 int setIndex = 0;
46 PyObject *v = PyStructSequence_New(&StructGrpType), *w;
47 char **member;
48
49 if (v == NULL)
50 return NULL;
51
52 if ((w = PyList_New(0)) == NULL) {
53 Py_DECREF(v);
54 return NULL;
55 }
56 for (member = p->gr_mem; *member != NULL; member++) {
57 PyObject *x = PyUnicode_DecodeFSDefault(*member);
58 if (x == NULL || PyList_Append(w, x) != 0) {
59 Py_XDECREF(x);
60 Py_DECREF(w);
61 Py_DECREF(v);
62 return NULL;
63 }
64 Py_DECREF(x);
65 }
66
67 #define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
68 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
69 if (p->gr_passwd)
70 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
71 else {
72 SET(setIndex++, Py_None);
73 Py_INCREF(Py_None);
74 }
75 SET(setIndex++, _PyLong_FromGid(p->gr_gid));
76 SET(setIndex++, w);
77 #undef SET
78
79 if (PyErr_Occurred()) {
80 Py_DECREF(v);
81 return NULL;
82 }
83
84 return v;
85 }
86
87 /*[clinic input]
88 grp.getgrgid
89
90 id: object
91
92 Return the group database entry for the given numeric group ID.
93
94 If id is not valid, raise KeyError.
95 [clinic start generated code]*/
96
97 static PyObject *
grp_getgrgid_impl(PyObject * module,PyObject * id)98 grp_getgrgid_impl(PyObject *module, PyObject *id)
99 /*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
100 {
101 PyObject *py_int_id, *retval = NULL;
102 int nomem = 0;
103 char *buf = NULL, *buf2 = NULL;
104 gid_t gid;
105 struct group *p;
106
107 if (!_Py_Gid_Converter(id, &gid)) {
108 if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
109 return NULL;
110 }
111 PyErr_Clear();
112 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
113 "group id must be int, not %.200",
114 id->ob_type->tp_name) < 0) {
115 return NULL;
116 }
117 py_int_id = PyNumber_Long(id);
118 if (!py_int_id)
119 return NULL;
120 if (!_Py_Gid_Converter(py_int_id, &gid)) {
121 Py_DECREF(py_int_id);
122 return NULL;
123 }
124 Py_DECREF(py_int_id);
125 }
126 #ifdef HAVE_GETGRGID_R
127 int status;
128 Py_ssize_t bufsize;
129 /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
130 struct group grp;
131
132 Py_BEGIN_ALLOW_THREADS
133 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
134 if (bufsize == -1) {
135 bufsize = DEFAULT_BUFFER_SIZE;
136 }
137
138 while (1) {
139 buf2 = PyMem_RawRealloc(buf, bufsize);
140 if (buf2 == NULL) {
141 p = NULL;
142 nomem = 1;
143 break;
144 }
145 buf = buf2;
146 status = getgrgid_r(gid, &grp, buf, bufsize, &p);
147 if (status != 0) {
148 p = NULL;
149 }
150 if (p != NULL || status != ERANGE) {
151 break;
152 }
153 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
154 nomem = 1;
155 break;
156 }
157 bufsize <<= 1;
158 }
159
160 Py_END_ALLOW_THREADS
161 #else
162 p = getgrgid(gid);
163 #endif
164 if (p == NULL) {
165 PyMem_RawFree(buf);
166 if (nomem == 1) {
167 return PyErr_NoMemory();
168 }
169 PyObject *gid_obj = _PyLong_FromGid(gid);
170 if (gid_obj == NULL)
171 return NULL;
172 PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
173 Py_DECREF(gid_obj);
174 return NULL;
175 }
176 retval = mkgrent(p);
177 #ifdef HAVE_GETGRGID_R
178 PyMem_RawFree(buf);
179 #endif
180 return retval;
181 }
182
183 /*[clinic input]
184 grp.getgrnam
185
186 name: unicode
187
188 Return the group database entry for the given group name.
189
190 If name is not valid, raise KeyError.
191 [clinic start generated code]*/
192
193 static PyObject *
grp_getgrnam_impl(PyObject * module,PyObject * name)194 grp_getgrnam_impl(PyObject *module, PyObject *name)
195 /*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
196 {
197 char *buf = NULL, *buf2 = NULL, *name_chars;
198 int nomem = 0;
199 struct group *p;
200 PyObject *bytes, *retval = NULL;
201
202 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
203 return NULL;
204 /* check for embedded null bytes */
205 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
206 goto out;
207 #ifdef HAVE_GETGRNAM_R
208 int status;
209 Py_ssize_t bufsize;
210 /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
211 struct group grp;
212
213 Py_BEGIN_ALLOW_THREADS
214 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
215 if (bufsize == -1) {
216 bufsize = DEFAULT_BUFFER_SIZE;
217 }
218
219 while(1) {
220 buf2 = PyMem_RawRealloc(buf, bufsize);
221 if (buf2 == NULL) {
222 p = NULL;
223 nomem = 1;
224 break;
225 }
226 buf = buf2;
227 status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
228 if (status != 0) {
229 p = NULL;
230 }
231 if (p != NULL || status != ERANGE) {
232 break;
233 }
234 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
235 nomem = 1;
236 break;
237 }
238 bufsize <<= 1;
239 }
240
241 Py_END_ALLOW_THREADS
242 #else
243 p = getgrnam(name_chars);
244 #endif
245 if (p == NULL) {
246 if (nomem == 1) {
247 PyErr_NoMemory();
248 }
249 else {
250 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
251 }
252 goto out;
253 }
254 retval = mkgrent(p);
255 out:
256 PyMem_RawFree(buf);
257 Py_DECREF(bytes);
258 return retval;
259 }
260
261 /*[clinic input]
262 grp.getgrall
263
264 Return a list of all available group entries, in arbitrary order.
265
266 An entry whose name starts with '+' or '-' represents an instruction
267 to use YP/NIS and may not be accessible via getgrnam or getgrgid.
268 [clinic start generated code]*/
269
270 static PyObject *
grp_getgrall_impl(PyObject * module)271 grp_getgrall_impl(PyObject *module)
272 /*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
273 {
274 PyObject *d;
275 struct group *p;
276
277 if ((d = PyList_New(0)) == NULL)
278 return NULL;
279 setgrent();
280 while ((p = getgrent()) != NULL) {
281 PyObject *v = mkgrent(p);
282 if (v == NULL || PyList_Append(d, v) != 0) {
283 Py_XDECREF(v);
284 Py_DECREF(d);
285 endgrent();
286 return NULL;
287 }
288 Py_DECREF(v);
289 }
290 endgrent();
291 return d;
292 }
293
294 static PyMethodDef grp_methods[] = {
295 GRP_GETGRGID_METHODDEF
296 GRP_GETGRNAM_METHODDEF
297 GRP_GETGRALL_METHODDEF
298 {NULL, NULL}
299 };
300
301 PyDoc_STRVAR(grp__doc__,
302 "Access to the Unix group database.\n\
303 \n\
304 Group entries are reported as 4-tuples containing the following fields\n\
305 from the group database, in order:\n\
306 \n\
307 gr_name - name of the group\n\
308 gr_passwd - group password (encrypted); often empty\n\
309 gr_gid - numeric ID of the group\n\
310 gr_mem - list of members\n\
311 \n\
312 The gid is an integer, name and password are strings. (Note that most\n\
313 users are not explicitly listed as members of the groups they are in\n\
314 according to the password database. Check both databases to get\n\
315 complete membership information.)");
316
317
318
319 static struct PyModuleDef grpmodule = {
320 PyModuleDef_HEAD_INIT,
321 "grp",
322 grp__doc__,
323 -1,
324 grp_methods,
325 NULL,
326 NULL,
327 NULL,
328 NULL
329 };
330
331 PyMODINIT_FUNC
PyInit_grp(void)332 PyInit_grp(void)
333 {
334 PyObject *m, *d;
335 m = PyModule_Create(&grpmodule);
336 if (m == NULL)
337 return NULL;
338 d = PyModule_GetDict(m);
339 if (!initialized) {
340 if (PyStructSequence_InitType2(&StructGrpType,
341 &struct_group_type_desc) < 0)
342 return NULL;
343 }
344 if (PyDict_SetItemString(d, "struct_group",
345 (PyObject *)&StructGrpType) < 0)
346 return NULL;
347 initialized = 1;
348 return m;
349 }
350