blob: f6298ca0ee84c135d03de2b0b582fac7f9387a0f [file] [log] [blame]
Guido van Rossum20882d51994-06-23 11:15:44 +00001
2/* UNIX group file access module */
3
Roger E. Masseb2b44e51996-12-18 19:37:32 +00004#include "Python.h"
Serhiy Storchaka7cf55992013-02-10 21:56:49 +02005#include "posixmodule.h"
Guido van Rossum20882d51994-06-23 11:15:44 +00006
Guido van Rossum20882d51994-06-23 11:15:44 +00007#include <grp.h>
8
Brett Cannon8fb7bb22014-08-22 11:52:46 -04009#include "clinic/grpmodule.c.h"
10/*[clinic input]
Brett Cannon8fb7bb22014-08-22 11:52:46 -040011module grp
12[clinic start generated code]*/
Serhiy Storchaka1009bf12015-04-03 23:53:51 +030013/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cade63f2ed1bd9f8]*/
Brett Cannon8fb7bb22014-08-22 11:52:46 -040014
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000015static PyStructSequence_Field struct_group_type_fields[] = {
16 {"gr_name", "group name"},
17 {"gr_passwd", "password"},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000018 {"gr_gid", "group id"},
Mark Dickinsonfb29a162013-08-05 17:57:01 +010019 {"gr_mem", "group members"},
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000020 {0}
21};
22
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000023PyDoc_STRVAR(struct_group__doc__,
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000024"grp.struct_group: Results from getgr*() routines.\n\n\
25This object may be accessed either as a tuple of\n\
26 (gr_name,gr_passwd,gr_gid,gr_mem)\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +000027or via the object attributes as named in the above tuple.\n");
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000028
29static PyStructSequence_Desc struct_group_type_desc = {
30 "grp.struct_group",
31 struct_group__doc__,
32 struct_group_type_fields,
33 4,
34};
35
36
Dino Viehland40a53132019-09-10 11:30:36 +010037typedef struct {
38 PyTypeObject *StructGrpType;
39} grpmodulestate;
Hai Shif707d942020-03-16 21:15:01 +080040
41static inline grpmodulestate*
42get_grp_state(PyObject *module)
43{
44 void *state = PyModule_GetState(module);
45 assert(state != NULL);
46 return (grpmodulestate *)state;
47}
48
Dino Viehland40a53132019-09-10 11:30:36 +010049static struct PyModuleDef grpmodule;
Fred Drake51b6bc52000-07-08 16:56:26 +000050
William Grzybowski23e65b22018-09-07 09:06:15 -030051#define DEFAULT_BUFFER_SIZE 1024
52
Fred Drake51b6bc52000-07-08 16:56:26 +000053static PyObject *
Christian Heimesfa2eee92020-11-19 08:47:32 +010054mkgrent(PyObject *module, struct group *p)
Guido van Rossum20882d51994-06-23 11:15:44 +000055{
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000056 int setIndex = 0;
Dino Viehland40a53132019-09-10 11:30:36 +010057 PyObject *v, *w;
Fred Drake51b6bc52000-07-08 16:56:26 +000058 char **member;
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000059
Christian Heimesfa2eee92020-11-19 08:47:32 +010060 v = PyStructSequence_New(get_grp_state(module)->StructGrpType);
61 if (v == NULL)
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000062 return NULL;
63
Fred Drake51b6bc52000-07-08 16:56:26 +000064 if ((w = PyList_New(0)) == NULL) {
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000065 Py_DECREF(v);
Fred Drake51b6bc52000-07-08 16:56:26 +000066 return NULL;
67 }
68 for (member = p->gr_mem; *member != NULL; member++) {
Victor Stinner97c18ab2010-05-07 16:34:53 +000069 PyObject *x = PyUnicode_DecodeFSDefault(*member);
Fred Drake51b6bc52000-07-08 16:56:26 +000070 if (x == NULL || PyList_Append(w, x) != 0) {
71 Py_XDECREF(x);
72 Py_DECREF(w);
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000073 Py_DECREF(v);
Fred Drake51b6bc52000-07-08 16:56:26 +000074 return NULL;
75 }
76 Py_DECREF(x);
77 }
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000078
79#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
Victor Stinner97c18ab2010-05-07 16:34:53 +000080 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000081 if (p->gr_passwd)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000083 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 SET(setIndex++, Py_None);
85 Py_INCREF(Py_None);
Martin v. Löwisceb7c182002-09-17 07:05:25 +000086 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +020087 SET(setIndex++, _PyLong_FromGid(p->gr_gid));
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000088 SET(setIndex++, w);
89#undef SET
90
91 if (PyErr_Occurred()) {
92 Py_DECREF(v);
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000093 return NULL;
94 }
95
Fred Drake51b6bc52000-07-08 16:56:26 +000096 return v;
Guido van Rossum20882d51994-06-23 11:15:44 +000097}
98
Brett Cannon8fb7bb22014-08-22 11:52:46 -040099/*[clinic input]
100grp.getgrgid
101
102 id: object
103
104Return the group database entry for the given numeric group ID.
105
106If id is not valid, raise KeyError.
107[clinic start generated code]*/
108
Fred Drake51b6bc52000-07-08 16:56:26 +0000109static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300110grp_getgrgid_impl(PyObject *module, PyObject *id)
111/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000112{
Serhiy Storchaka578c3952020-05-26 18:43:38 +0300113 PyObject *retval = NULL;
William Grzybowski23e65b22018-09-07 09:06:15 -0300114 int nomem = 0;
115 char *buf = NULL, *buf2 = NULL;
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200116 gid_t gid;
Fred Drake51b6bc52000-07-08 16:56:26 +0000117 struct group *p;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000118
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200119 if (!_Py_Gid_Converter(id, &gid)) {
Serhiy Storchaka578c3952020-05-26 18:43:38 +0300120 return NULL;
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200121 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300122#ifdef HAVE_GETGRGID_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300123 int status;
124 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300125 /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300126 struct group grp;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000127
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300128 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300129 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 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200165 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);
Fred Drake51b6bc52000-07-08 16:56:26 +0000170 return NULL;
171 }
Christian Heimesfa2eee92020-11-19 08:47:32 +0100172 retval = mkgrent(module, p);
William Grzybowski23e65b22018-09-07 09:06:15 -0300173#ifdef HAVE_GETGRGID_R
174 PyMem_RawFree(buf);
175#endif
176 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000177}
178
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400179/*[clinic input]
180grp.getgrnam
Thomas Wouters477c8d52006-05-27 19:21:47 +0000181
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400182 name: unicode
183
184Return the group database entry for the given group name.
185
186If name is not valid, raise KeyError.
187[clinic start generated code]*/
188
189static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300190grp_getgrnam_impl(PyObject *module, PyObject *name)
191/*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400192{
William Grzybowski23e65b22018-09-07 09:06:15 -0300193 char *buf = NULL, *buf2 = NULL, *name_chars;
194 int nomem = 0;
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400195 struct group *p;
196 PyObject *bytes, *retval = NULL;
197
198 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000199 return NULL;
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300200 /* check for embedded null bytes */
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400201 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000202 goto out;
William Grzybowski23e65b22018-09-07 09:06:15 -0300203#ifdef HAVE_GETGRNAM_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300204 int status;
205 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300206 /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300207 struct group grp;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300209 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300210 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 {
William Grzybowski34c7f0c2018-12-05 17:10:18 -0200246 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
William Grzybowski23e65b22018-09-07 09:06:15 -0300247 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000248 goto out;
Fred Drake51b6bc52000-07-08 16:56:26 +0000249 }
Christian Heimesfa2eee92020-11-19 08:47:32 +0100250 retval = mkgrent(module, p);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000251out:
William Grzybowski23e65b22018-09-07 09:06:15 -0300252 PyMem_RawFree(buf);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000253 Py_DECREF(bytes);
254 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000255}
256
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400257/*[clinic input]
258grp.getgrall
259
260Return a list of all available group entries, in arbitrary order.
261
262An entry whose name starts with '+' or '-' represents an instruction
263to use YP/NIS and may not be accessible via getgrnam or getgrgid.
264[clinic start generated code]*/
265
Fred Drake51b6bc52000-07-08 16:56:26 +0000266static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300267grp_getgrall_impl(PyObject *module)
268/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000269{
Fred Drake51b6bc52000-07-08 16:56:26 +0000270 PyObject *d;
271 struct group *p;
272
Fred Drake51b6bc52000-07-08 16:56:26 +0000273 if ((d = PyList_New(0)) == NULL)
274 return NULL;
275 setgrent();
276 while ((p = getgrent()) != NULL) {
Christian Heimesfa2eee92020-11-19 08:47:32 +0100277 PyObject *v = mkgrent(module, p);
Fred Drake51b6bc52000-07-08 16:56:26 +0000278 if (v == NULL || PyList_Append(d, v) != 0) {
279 Py_XDECREF(v);
280 Py_DECREF(d);
Martin v. Löwise23c8682009-05-29 16:01:34 +0000281 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000282 return NULL;
283 }
284 Py_DECREF(v);
285 }
Fred Drake8e68eb62001-03-11 03:03:07 +0000286 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000287 return d;
Guido van Rossum20882d51994-06-23 11:15:44 +0000288}
289
Roger E. Masseb2b44e51996-12-18 19:37:32 +0000290static PyMethodDef grp_methods[] = {
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400291 GRP_GETGRGID_METHODDEF
292 GRP_GETGRNAM_METHODDEF
293 GRP_GETGRALL_METHODDEF
294 {NULL, NULL}
Guido van Rossum20882d51994-06-23 11:15:44 +0000295};
296
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000297PyDoc_STRVAR(grp__doc__,
Fred Drake51b6bc52000-07-08 16:56:26 +0000298"Access to the Unix group database.\n\
299\n\
300Group entries are reported as 4-tuples containing the following fields\n\
301from the group database, in order:\n\
302\n\
Georg Brandl41ea1f42014-10-02 08:34:41 +0200303 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\
Fred Drake51b6bc52000-07-08 16:56:26 +0000307\n\
308The gid is an integer, name and password are strings. (Note that most\n\
309users are not explicitly listed as members of the groups they are in\n\
310according to the password database. Check both databases to get\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000311complete membership information.)");
Fred Drake51b6bc52000-07-08 16:56:26 +0000312
Christian Heimesfa2eee92020-11-19 08:47:32 +0100313static int
314grpmodule_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
328static PyModuleDef_Slot grpmodule_slots[] = {
329 {Py_mod_exec, grpmodule_exec},
330 {0, NULL}
331};
332
Dino Viehland40a53132019-09-10 11:30:36 +0100333static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
Hai Shif707d942020-03-16 21:15:01 +0800334 Py_VISIT(get_grp_state(m)->StructGrpType);
Dino Viehland40a53132019-09-10 11:30:36 +0100335 return 0;
336}
Fred Drake51b6bc52000-07-08 16:56:26 +0000337
Dino Viehland40a53132019-09-10 11:30:36 +0100338static int grpmodule_clear(PyObject *m) {
Hai Shif707d942020-03-16 21:15:01 +0800339 Py_CLEAR(get_grp_state(m)->StructGrpType);
Dino Viehland40a53132019-09-10 11:30:36 +0100340 return 0;
341}
342
343static void grpmodule_free(void *m) {
344 grpmodule_clear((PyObject *)m);
345}
Martin v. Löwis1a214512008-06-11 05:26:20 +0000346
347static struct PyModuleDef grpmodule = {
Christian Heimesfa2eee92020-11-19 08:47:32 +0100348 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,
Martin v. Löwis1a214512008-06-11 05:26:20 +0000357};
358
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000359PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000360PyInit_grp(void)
Guido van Rossum20882d51994-06-23 11:15:44 +0000361{
Christian Heimesfa2eee92020-11-19 08:47:32 +0100362 return PyModuleDef_Init(&grpmodule);
Guido van Rossum20882d51994-06-23 11:15:44 +0000363}