blob: c4d16819e487aacf44cda28311d8924b86a496c2 [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{
Serhiy Storchaka578c3952020-05-26 18:43:38 +0300114 PyObject *retval = NULL;
William Grzybowski23e65b22018-09-07 09:06:15 -0300115 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)) {
Serhiy Storchaka578c3952020-05-26 18:43:38 +0300121 return NULL;
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200122 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300123#ifdef HAVE_GETGRGID_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300124 int status;
125 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300126 /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300127 struct group grp;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000128
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300129 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300130 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
131 if (bufsize == -1) {
132 bufsize = DEFAULT_BUFFER_SIZE;
133 }
134
135 while (1) {
136 buf2 = PyMem_RawRealloc(buf, bufsize);
137 if (buf2 == NULL) {
138 p = NULL;
139 nomem = 1;
140 break;
141 }
142 buf = buf2;
143 status = getgrgid_r(gid, &grp, buf, bufsize, &p);
144 if (status != 0) {
145 p = NULL;
146 }
147 if (p != NULL || status != ERANGE) {
148 break;
149 }
150 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
151 nomem = 1;
152 break;
153 }
154 bufsize <<= 1;
155 }
156
157 Py_END_ALLOW_THREADS
158#else
159 p = getgrgid(gid);
160#endif
161 if (p == NULL) {
162 PyMem_RawFree(buf);
163 if (nomem == 1) {
164 return PyErr_NoMemory();
165 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200166 PyObject *gid_obj = _PyLong_FromGid(gid);
167 if (gid_obj == NULL)
168 return NULL;
169 PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
170 Py_DECREF(gid_obj);
Fred Drake51b6bc52000-07-08 16:56:26 +0000171 return NULL;
172 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300173 retval = mkgrent(p);
174#ifdef HAVE_GETGRGID_R
175 PyMem_RawFree(buf);
176#endif
177 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000178}
179
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400180/*[clinic input]
181grp.getgrnam
Thomas Wouters477c8d52006-05-27 19:21:47 +0000182
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400183 name: unicode
184
185Return the group database entry for the given group name.
186
187If name is not valid, raise KeyError.
188[clinic start generated code]*/
189
190static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300191grp_getgrnam_impl(PyObject *module, PyObject *name)
192/*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400193{
William Grzybowski23e65b22018-09-07 09:06:15 -0300194 char *buf = NULL, *buf2 = NULL, *name_chars;
195 int nomem = 0;
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400196 struct group *p;
197 PyObject *bytes, *retval = NULL;
198
199 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000200 return NULL;
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300201 /* check for embedded null bytes */
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400202 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000203 goto out;
William Grzybowski23e65b22018-09-07 09:06:15 -0300204#ifdef HAVE_GETGRNAM_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300205 int status;
206 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300207 /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300208 struct group grp;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300210 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300211 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
212 if (bufsize == -1) {
213 bufsize = DEFAULT_BUFFER_SIZE;
214 }
215
216 while(1) {
217 buf2 = PyMem_RawRealloc(buf, bufsize);
218 if (buf2 == NULL) {
219 p = NULL;
220 nomem = 1;
221 break;
222 }
223 buf = buf2;
224 status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
225 if (status != 0) {
226 p = NULL;
227 }
228 if (p != NULL || status != ERANGE) {
229 break;
230 }
231 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
232 nomem = 1;
233 break;
234 }
235 bufsize <<= 1;
236 }
237
238 Py_END_ALLOW_THREADS
239#else
240 p = getgrnam(name_chars);
241#endif
242 if (p == NULL) {
243 if (nomem == 1) {
244 PyErr_NoMemory();
245 }
246 else {
William Grzybowski34c7f0c2018-12-05 17:10:18 -0200247 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
William Grzybowski23e65b22018-09-07 09:06:15 -0300248 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000249 goto out;
Fred Drake51b6bc52000-07-08 16:56:26 +0000250 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000251 retval = mkgrent(p);
252out:
William Grzybowski23e65b22018-09-07 09:06:15 -0300253 PyMem_RawFree(buf);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000254 Py_DECREF(bytes);
255 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000256}
257
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400258/*[clinic input]
259grp.getgrall
260
261Return a list of all available group entries, in arbitrary order.
262
263An entry whose name starts with '+' or '-' represents an instruction
264to use YP/NIS and may not be accessible via getgrnam or getgrgid.
265[clinic start generated code]*/
266
Fred Drake51b6bc52000-07-08 16:56:26 +0000267static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300268grp_getgrall_impl(PyObject *module)
269/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000270{
Fred Drake51b6bc52000-07-08 16:56:26 +0000271 PyObject *d;
272 struct group *p;
273
Fred Drake51b6bc52000-07-08 16:56:26 +0000274 if ((d = PyList_New(0)) == NULL)
275 return NULL;
276 setgrent();
277 while ((p = getgrent()) != NULL) {
278 PyObject *v = mkgrent(p);
279 if (v == NULL || PyList_Append(d, v) != 0) {
280 Py_XDECREF(v);
281 Py_DECREF(d);
Martin v. Löwise23c8682009-05-29 16:01:34 +0000282 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000283 return NULL;
284 }
285 Py_DECREF(v);
286 }
Fred Drake8e68eb62001-03-11 03:03:07 +0000287 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000288 return d;
Guido van Rossum20882d51994-06-23 11:15:44 +0000289}
290
Roger E. Masseb2b44e51996-12-18 19:37:32 +0000291static PyMethodDef grp_methods[] = {
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400292 GRP_GETGRGID_METHODDEF
293 GRP_GETGRNAM_METHODDEF
294 GRP_GETGRALL_METHODDEF
295 {NULL, NULL}
Guido van Rossum20882d51994-06-23 11:15:44 +0000296};
297
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000298PyDoc_STRVAR(grp__doc__,
Fred Drake51b6bc52000-07-08 16:56:26 +0000299"Access to the Unix group database.\n\
300\n\
301Group entries are reported as 4-tuples containing the following fields\n\
302from the group database, in order:\n\
303\n\
Georg Brandl41ea1f42014-10-02 08:34:41 +0200304 gr_name - name of the group\n\
305 gr_passwd - group password (encrypted); often empty\n\
306 gr_gid - numeric ID of the group\n\
307 gr_mem - list of members\n\
Fred Drake51b6bc52000-07-08 16:56:26 +0000308\n\
309The gid is an integer, name and password are strings. (Note that most\n\
310users are not explicitly listed as members of the groups they are in\n\
311according to the password database. Check both databases to get\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000312complete membership information.)");
Fred Drake51b6bc52000-07-08 16:56:26 +0000313
Dino Viehland40a53132019-09-10 11:30:36 +0100314static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
Hai Shif707d942020-03-16 21:15:01 +0800315 Py_VISIT(get_grp_state(m)->StructGrpType);
Dino Viehland40a53132019-09-10 11:30:36 +0100316 return 0;
317}
Fred Drake51b6bc52000-07-08 16:56:26 +0000318
Dino Viehland40a53132019-09-10 11:30:36 +0100319static int grpmodule_clear(PyObject *m) {
Hai Shif707d942020-03-16 21:15:01 +0800320 Py_CLEAR(get_grp_state(m)->StructGrpType);
Dino Viehland40a53132019-09-10 11:30:36 +0100321 return 0;
322}
323
324static void grpmodule_free(void *m) {
325 grpmodule_clear((PyObject *)m);
326}
Martin v. Löwis1a214512008-06-11 05:26:20 +0000327
328static struct PyModuleDef grpmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 PyModuleDef_HEAD_INIT,
330 "grp",
331 grp__doc__,
Dino Viehland40a53132019-09-10 11:30:36 +0100332 sizeof(grpmodulestate),
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 grp_methods,
334 NULL,
Dino Viehland40a53132019-09-10 11:30:36 +0100335 grpmodule_traverse,
336 grpmodule_clear,
337 grpmodule_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +0000338};
339
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000340PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000341PyInit_grp(void)
Guido van Rossum20882d51994-06-23 11:15:44 +0000342{
Dino Viehland40a53132019-09-10 11:30:36 +0100343 PyObject *m;
344 if ((m = PyState_FindModule(&grpmodule)) != NULL) {
345 Py_INCREF(m);
346 return m;
Victor Stinner1c8f0592013-07-22 22:24:54 +0200347 }
Dino Viehland40a53132019-09-10 11:30:36 +0100348
349 if ((m = PyModule_Create(&grpmodule)) == NULL) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200350 return NULL;
Dino Viehland40a53132019-09-10 11:30:36 +0100351 }
352
353 grpmodulestate *state = PyModule_GetState(m);
354 state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc);
355 if (state->StructGrpType == NULL) {
356 return NULL;
357 }
358
359 Py_INCREF(state->StructGrpType);
360 PyModule_AddObject(m, "struct_group", (PyObject *) state->StructGrpType);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000361 return m;
Guido van Rossum20882d51994-06-23 11:15:44 +0000362}