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 != 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 * |
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 * |
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 * |
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 |
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 | |
333 | static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) { |
334 | Py_VISIT(get_grp_state(m)->StructGrpType); |
335 | return 0; |
336 | } |
337 | |
338 | static int grpmodule_clear(PyObject *m) { |
339 | Py_CLEAR(get_grp_state(m)->StructGrpType); |
340 | return 0; |
341 | } |
342 | |
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 |
360 | PyInit_grp(void) |
361 | { |
362 | return PyModuleDef_Init(&grpmodule); |
363 | } |
364 | |