blob: cdb3ae859b3893fff505dd5ab38768f9723a0b6a [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
49#define modulestate_global get_grp_state(PyState_FindModule(&grpmodule))
Dino Viehland40a53132019-09-10 11:30:36 +010050
51static struct PyModuleDef grpmodule;
Fred Drake51b6bc52000-07-08 16:56:26 +000052
William Grzybowski23e65b22018-09-07 09:06:15 -030053#define DEFAULT_BUFFER_SIZE 1024
54
Fred Drake51b6bc52000-07-08 16:56:26 +000055static PyObject *
56mkgrent(struct group *p)
Guido van Rossum20882d51994-06-23 11:15:44 +000057{
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000058 int setIndex = 0;
Dino Viehland40a53132019-09-10 11:30:36 +010059 PyObject *v, *w;
Fred Drake51b6bc52000-07-08 16:56:26 +000060 char **member;
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000061
Dino Viehland40a53132019-09-10 11:30:36 +010062 if ((v = PyStructSequence_New(modulestate_global->StructGrpType)) == NULL)
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000063 return NULL;
64
Fred Drake51b6bc52000-07-08 16:56:26 +000065 if ((w = PyList_New(0)) == NULL) {
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000066 Py_DECREF(v);
Fred Drake51b6bc52000-07-08 16:56:26 +000067 return NULL;
68 }
69 for (member = p->gr_mem; *member != NULL; member++) {
Victor Stinner97c18ab2010-05-07 16:34:53 +000070 PyObject *x = PyUnicode_DecodeFSDefault(*member);
Fred Drake51b6bc52000-07-08 16:56:26 +000071 if (x == NULL || PyList_Append(w, x) != 0) {
72 Py_XDECREF(x);
73 Py_DECREF(w);
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000074 Py_DECREF(v);
Fred Drake51b6bc52000-07-08 16:56:26 +000075 return NULL;
76 }
77 Py_DECREF(x);
78 }
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000079
80#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
Victor Stinner97c18ab2010-05-07 16:34:53 +000081 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000082 if (p->gr_passwd)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000083 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000084 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000085 SET(setIndex++, Py_None);
86 Py_INCREF(Py_None);
Martin v. Löwisceb7c182002-09-17 07:05:25 +000087 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +020088 SET(setIndex++, _PyLong_FromGid(p->gr_gid));
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000089 SET(setIndex++, w);
90#undef SET
91
92 if (PyErr_Occurred()) {
93 Py_DECREF(v);
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000094 return NULL;
95 }
96
Fred Drake51b6bc52000-07-08 16:56:26 +000097 return v;
Guido van Rossum20882d51994-06-23 11:15:44 +000098}
99
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400100/*[clinic input]
101grp.getgrgid
102
103 id: object
104
105Return the group database entry for the given numeric group ID.
106
107If id is not valid, raise KeyError.
108[clinic start generated code]*/
109
Fred Drake51b6bc52000-07-08 16:56:26 +0000110static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300111grp_getgrgid_impl(PyObject *module, PyObject *id)
112/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000113{
William Grzybowski23e65b22018-09-07 09:06:15 -0300114 PyObject *py_int_id, *retval = NULL;
115 int nomem = 0;
116 char *buf = NULL, *buf2 = NULL;
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200117 gid_t gid;
Fred Drake51b6bc52000-07-08 16:56:26 +0000118 struct group *p;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000119
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200120 if (!_Py_Gid_Converter(id, &gid)) {
121 if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000122 return NULL;
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200123 }
124 PyErr_Clear();
125 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
126 "group id must be int, not %.200",
Victor Stinnerdaa97562020-02-07 03:37:06 +0100127 Py_TYPE(id)->tp_name) < 0) {
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200128 return NULL;
129 }
130 py_int_id = PyNumber_Long(id);
131 if (!py_int_id)
132 return NULL;
133 if (!_Py_Gid_Converter(py_int_id, &gid)) {
134 Py_DECREF(py_int_id);
135 return NULL;
136 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200137 Py_DECREF(py_int_id);
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200138 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300139#ifdef HAVE_GETGRGID_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300140 int status;
141 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300142 /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300143 struct group grp;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000144
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300145 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300146 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
147 if (bufsize == -1) {
148 bufsize = DEFAULT_BUFFER_SIZE;
149 }
150
151 while (1) {
152 buf2 = PyMem_RawRealloc(buf, bufsize);
153 if (buf2 == NULL) {
154 p = NULL;
155 nomem = 1;
156 break;
157 }
158 buf = buf2;
159 status = getgrgid_r(gid, &grp, buf, bufsize, &p);
160 if (status != 0) {
161 p = NULL;
162 }
163 if (p != NULL || status != ERANGE) {
164 break;
165 }
166 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
167 nomem = 1;
168 break;
169 }
170 bufsize <<= 1;
171 }
172
173 Py_END_ALLOW_THREADS
174#else
175 p = getgrgid(gid);
176#endif
177 if (p == NULL) {
178 PyMem_RawFree(buf);
179 if (nomem == 1) {
180 return PyErr_NoMemory();
181 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200182 PyObject *gid_obj = _PyLong_FromGid(gid);
183 if (gid_obj == NULL)
184 return NULL;
185 PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
186 Py_DECREF(gid_obj);
Fred Drake51b6bc52000-07-08 16:56:26 +0000187 return NULL;
188 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300189 retval = mkgrent(p);
190#ifdef HAVE_GETGRGID_R
191 PyMem_RawFree(buf);
192#endif
193 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000194}
195
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400196/*[clinic input]
197grp.getgrnam
Thomas Wouters477c8d52006-05-27 19:21:47 +0000198
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400199 name: unicode
200
201Return the group database entry for the given group name.
202
203If name is not valid, raise KeyError.
204[clinic start generated code]*/
205
206static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300207grp_getgrnam_impl(PyObject *module, PyObject *name)
208/*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400209{
William Grzybowski23e65b22018-09-07 09:06:15 -0300210 char *buf = NULL, *buf2 = NULL, *name_chars;
211 int nomem = 0;
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400212 struct group *p;
213 PyObject *bytes, *retval = NULL;
214
215 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000216 return NULL;
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300217 /* check for embedded null bytes */
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400218 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000219 goto out;
William Grzybowski23e65b22018-09-07 09:06:15 -0300220#ifdef HAVE_GETGRNAM_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300221 int status;
222 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300223 /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300224 struct group grp;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300226 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300227 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
228 if (bufsize == -1) {
229 bufsize = DEFAULT_BUFFER_SIZE;
230 }
231
232 while(1) {
233 buf2 = PyMem_RawRealloc(buf, bufsize);
234 if (buf2 == NULL) {
235 p = NULL;
236 nomem = 1;
237 break;
238 }
239 buf = buf2;
240 status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
241 if (status != 0) {
242 p = NULL;
243 }
244 if (p != NULL || status != ERANGE) {
245 break;
246 }
247 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
248 nomem = 1;
249 break;
250 }
251 bufsize <<= 1;
252 }
253
254 Py_END_ALLOW_THREADS
255#else
256 p = getgrnam(name_chars);
257#endif
258 if (p == NULL) {
259 if (nomem == 1) {
260 PyErr_NoMemory();
261 }
262 else {
William Grzybowski34c7f0c2018-12-05 17:10:18 -0200263 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
William Grzybowski23e65b22018-09-07 09:06:15 -0300264 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000265 goto out;
Fred Drake51b6bc52000-07-08 16:56:26 +0000266 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000267 retval = mkgrent(p);
268out:
William Grzybowski23e65b22018-09-07 09:06:15 -0300269 PyMem_RawFree(buf);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000270 Py_DECREF(bytes);
271 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000272}
273
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400274/*[clinic input]
275grp.getgrall
276
277Return a list of all available group entries, in arbitrary order.
278
279An entry whose name starts with '+' or '-' represents an instruction
280to use YP/NIS and may not be accessible via getgrnam or getgrgid.
281[clinic start generated code]*/
282
Fred Drake51b6bc52000-07-08 16:56:26 +0000283static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300284grp_getgrall_impl(PyObject *module)
285/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000286{
Fred Drake51b6bc52000-07-08 16:56:26 +0000287 PyObject *d;
288 struct group *p;
289
Fred Drake51b6bc52000-07-08 16:56:26 +0000290 if ((d = PyList_New(0)) == NULL)
291 return NULL;
292 setgrent();
293 while ((p = getgrent()) != NULL) {
294 PyObject *v = mkgrent(p);
295 if (v == NULL || PyList_Append(d, v) != 0) {
296 Py_XDECREF(v);
297 Py_DECREF(d);
Martin v. Löwise23c8682009-05-29 16:01:34 +0000298 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000299 return NULL;
300 }
301 Py_DECREF(v);
302 }
Fred Drake8e68eb62001-03-11 03:03:07 +0000303 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000304 return d;
Guido van Rossum20882d51994-06-23 11:15:44 +0000305}
306
Roger E. Masseb2b44e51996-12-18 19:37:32 +0000307static PyMethodDef grp_methods[] = {
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400308 GRP_GETGRGID_METHODDEF
309 GRP_GETGRNAM_METHODDEF
310 GRP_GETGRALL_METHODDEF
311 {NULL, NULL}
Guido van Rossum20882d51994-06-23 11:15:44 +0000312};
313
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000314PyDoc_STRVAR(grp__doc__,
Fred Drake51b6bc52000-07-08 16:56:26 +0000315"Access to the Unix group database.\n\
316\n\
317Group entries are reported as 4-tuples containing the following fields\n\
318from the group database, in order:\n\
319\n\
Georg Brandl41ea1f42014-10-02 08:34:41 +0200320 gr_name - name of the group\n\
321 gr_passwd - group password (encrypted); often empty\n\
322 gr_gid - numeric ID of the group\n\
323 gr_mem - list of members\n\
Fred Drake51b6bc52000-07-08 16:56:26 +0000324\n\
325The gid is an integer, name and password are strings. (Note that most\n\
326users are not explicitly listed as members of the groups they are in\n\
327according to the password database. Check both databases to get\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000328complete membership information.)");
Fred Drake51b6bc52000-07-08 16:56:26 +0000329
Dino Viehland40a53132019-09-10 11:30:36 +0100330static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
Hai Shif707d942020-03-16 21:15:01 +0800331 Py_VISIT(get_grp_state(m)->StructGrpType);
Dino Viehland40a53132019-09-10 11:30:36 +0100332 return 0;
333}
Fred Drake51b6bc52000-07-08 16:56:26 +0000334
Dino Viehland40a53132019-09-10 11:30:36 +0100335static int grpmodule_clear(PyObject *m) {
Hai Shif707d942020-03-16 21:15:01 +0800336 Py_CLEAR(get_grp_state(m)->StructGrpType);
Dino Viehland40a53132019-09-10 11:30:36 +0100337 return 0;
338}
339
340static void grpmodule_free(void *m) {
341 grpmodule_clear((PyObject *)m);
342}
Martin v. Löwis1a214512008-06-11 05:26:20 +0000343
344static struct PyModuleDef grpmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000345 PyModuleDef_HEAD_INIT,
346 "grp",
347 grp__doc__,
Dino Viehland40a53132019-09-10 11:30:36 +0100348 sizeof(grpmodulestate),
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 grp_methods,
350 NULL,
Dino Viehland40a53132019-09-10 11:30:36 +0100351 grpmodule_traverse,
352 grpmodule_clear,
353 grpmodule_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +0000354};
355
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000356PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000357PyInit_grp(void)
Guido van Rossum20882d51994-06-23 11:15:44 +0000358{
Dino Viehland40a53132019-09-10 11:30:36 +0100359 PyObject *m;
360 if ((m = PyState_FindModule(&grpmodule)) != NULL) {
361 Py_INCREF(m);
362 return m;
Victor Stinner1c8f0592013-07-22 22:24:54 +0200363 }
Dino Viehland40a53132019-09-10 11:30:36 +0100364
365 if ((m = PyModule_Create(&grpmodule)) == NULL) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200366 return NULL;
Dino Viehland40a53132019-09-10 11:30:36 +0100367 }
368
369 grpmodulestate *state = PyModule_GetState(m);
370 state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc);
371 if (state->StructGrpType == NULL) {
372 return NULL;
373 }
374
375 Py_INCREF(state->StructGrpType);
376 PyModule_AddObject(m, "struct_group", (PyObject *) state->StructGrpType);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000377 return m;
Guido van Rossum20882d51994-06-23 11:15:44 +0000378}