blob: 0e2801fce5055cf51c1cc43f42e3f02c3a563f1a [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;
40#define modulestate(o) ((grpmodulestate *)PyModule_GetState(o))
41#define modulestate_global modulestate(PyState_FindModule(&grpmodule))
42
43static struct PyModuleDef grpmodule;
Fred Drake51b6bc52000-07-08 16:56:26 +000044
William Grzybowski23e65b22018-09-07 09:06:15 -030045#define DEFAULT_BUFFER_SIZE 1024
46
Fred Drake51b6bc52000-07-08 16:56:26 +000047static PyObject *
48mkgrent(struct group *p)
Guido van Rossum20882d51994-06-23 11:15:44 +000049{
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000050 int setIndex = 0;
Dino Viehland40a53132019-09-10 11:30:36 +010051 PyObject *v, *w;
Fred Drake51b6bc52000-07-08 16:56:26 +000052 char **member;
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000053
Dino Viehland40a53132019-09-10 11:30:36 +010054 if ((v = PyStructSequence_New(modulestate_global->StructGrpType)) == NULL)
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000055 return NULL;
56
Fred Drake51b6bc52000-07-08 16:56:26 +000057 if ((w = PyList_New(0)) == NULL) {
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000058 Py_DECREF(v);
Fred Drake51b6bc52000-07-08 16:56:26 +000059 return NULL;
60 }
61 for (member = p->gr_mem; *member != NULL; member++) {
Victor Stinner97c18ab2010-05-07 16:34:53 +000062 PyObject *x = PyUnicode_DecodeFSDefault(*member);
Fred Drake51b6bc52000-07-08 16:56:26 +000063 if (x == NULL || PyList_Append(w, x) != 0) {
64 Py_XDECREF(x);
65 Py_DECREF(w);
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 Py_DECREF(x);
70 }
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000071
72#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
Victor Stinner97c18ab2010-05-07 16:34:53 +000073 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000074 if (p->gr_passwd)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000075 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000076 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000077 SET(setIndex++, Py_None);
78 Py_INCREF(Py_None);
Martin v. Löwisceb7c182002-09-17 07:05:25 +000079 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +020080 SET(setIndex++, _PyLong_FromGid(p->gr_gid));
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000081 SET(setIndex++, w);
82#undef SET
83
84 if (PyErr_Occurred()) {
85 Py_DECREF(v);
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000086 return NULL;
87 }
88
Fred Drake51b6bc52000-07-08 16:56:26 +000089 return v;
Guido van Rossum20882d51994-06-23 11:15:44 +000090}
91
Brett Cannon8fb7bb22014-08-22 11:52:46 -040092/*[clinic input]
93grp.getgrgid
94
95 id: object
96
97Return the group database entry for the given numeric group ID.
98
99If id is not valid, raise KeyError.
100[clinic start generated code]*/
101
Fred Drake51b6bc52000-07-08 16:56:26 +0000102static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300103grp_getgrgid_impl(PyObject *module, PyObject *id)
104/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000105{
William Grzybowski23e65b22018-09-07 09:06:15 -0300106 PyObject *py_int_id, *retval = NULL;
107 int nomem = 0;
108 char *buf = NULL, *buf2 = NULL;
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200109 gid_t gid;
Fred Drake51b6bc52000-07-08 16:56:26 +0000110 struct group *p;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000111
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200112 if (!_Py_Gid_Converter(id, &gid)) {
113 if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000114 return NULL;
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200115 }
116 PyErr_Clear();
117 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
118 "group id must be int, not %.200",
Victor Stinnerdaa97562020-02-07 03:37:06 +0100119 Py_TYPE(id)->tp_name) < 0) {
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200120 return NULL;
121 }
122 py_int_id = PyNumber_Long(id);
123 if (!py_int_id)
124 return NULL;
125 if (!_Py_Gid_Converter(py_int_id, &gid)) {
126 Py_DECREF(py_int_id);
127 return NULL;
128 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200129 Py_DECREF(py_int_id);
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200130 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300131#ifdef HAVE_GETGRGID_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300132 int status;
133 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300134 /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300135 struct group grp;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000136
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300137 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300138 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
139 if (bufsize == -1) {
140 bufsize = DEFAULT_BUFFER_SIZE;
141 }
142
143 while (1) {
144 buf2 = PyMem_RawRealloc(buf, bufsize);
145 if (buf2 == NULL) {
146 p = NULL;
147 nomem = 1;
148 break;
149 }
150 buf = buf2;
151 status = getgrgid_r(gid, &grp, buf, bufsize, &p);
152 if (status != 0) {
153 p = NULL;
154 }
155 if (p != NULL || status != ERANGE) {
156 break;
157 }
158 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
159 nomem = 1;
160 break;
161 }
162 bufsize <<= 1;
163 }
164
165 Py_END_ALLOW_THREADS
166#else
167 p = getgrgid(gid);
168#endif
169 if (p == NULL) {
170 PyMem_RawFree(buf);
171 if (nomem == 1) {
172 return PyErr_NoMemory();
173 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200174 PyObject *gid_obj = _PyLong_FromGid(gid);
175 if (gid_obj == NULL)
176 return NULL;
177 PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
178 Py_DECREF(gid_obj);
Fred Drake51b6bc52000-07-08 16:56:26 +0000179 return NULL;
180 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300181 retval = mkgrent(p);
182#ifdef HAVE_GETGRGID_R
183 PyMem_RawFree(buf);
184#endif
185 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000186}
187
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400188/*[clinic input]
189grp.getgrnam
Thomas Wouters477c8d52006-05-27 19:21:47 +0000190
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400191 name: unicode
192
193Return the group database entry for the given group name.
194
195If name is not valid, raise KeyError.
196[clinic start generated code]*/
197
198static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300199grp_getgrnam_impl(PyObject *module, PyObject *name)
200/*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400201{
William Grzybowski23e65b22018-09-07 09:06:15 -0300202 char *buf = NULL, *buf2 = NULL, *name_chars;
203 int nomem = 0;
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400204 struct group *p;
205 PyObject *bytes, *retval = NULL;
206
207 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000208 return NULL;
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300209 /* check for embedded null bytes */
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400210 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000211 goto out;
William Grzybowski23e65b22018-09-07 09:06:15 -0300212#ifdef HAVE_GETGRNAM_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300213 int status;
214 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300215 /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300216 struct group grp;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300218 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300219 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
220 if (bufsize == -1) {
221 bufsize = DEFAULT_BUFFER_SIZE;
222 }
223
224 while(1) {
225 buf2 = PyMem_RawRealloc(buf, bufsize);
226 if (buf2 == NULL) {
227 p = NULL;
228 nomem = 1;
229 break;
230 }
231 buf = buf2;
232 status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
233 if (status != 0) {
234 p = NULL;
235 }
236 if (p != NULL || status != ERANGE) {
237 break;
238 }
239 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
240 nomem = 1;
241 break;
242 }
243 bufsize <<= 1;
244 }
245
246 Py_END_ALLOW_THREADS
247#else
248 p = getgrnam(name_chars);
249#endif
250 if (p == NULL) {
251 if (nomem == 1) {
252 PyErr_NoMemory();
253 }
254 else {
William Grzybowski34c7f0c2018-12-05 17:10:18 -0200255 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
William Grzybowski23e65b22018-09-07 09:06:15 -0300256 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000257 goto out;
Fred Drake51b6bc52000-07-08 16:56:26 +0000258 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000259 retval = mkgrent(p);
260out:
William Grzybowski23e65b22018-09-07 09:06:15 -0300261 PyMem_RawFree(buf);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000262 Py_DECREF(bytes);
263 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000264}
265
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400266/*[clinic input]
267grp.getgrall
268
269Return a list of all available group entries, in arbitrary order.
270
271An entry whose name starts with '+' or '-' represents an instruction
272to use YP/NIS and may not be accessible via getgrnam or getgrgid.
273[clinic start generated code]*/
274
Fred Drake51b6bc52000-07-08 16:56:26 +0000275static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300276grp_getgrall_impl(PyObject *module)
277/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000278{
Fred Drake51b6bc52000-07-08 16:56:26 +0000279 PyObject *d;
280 struct group *p;
281
Fred Drake51b6bc52000-07-08 16:56:26 +0000282 if ((d = PyList_New(0)) == NULL)
283 return NULL;
284 setgrent();
285 while ((p = getgrent()) != NULL) {
286 PyObject *v = mkgrent(p);
287 if (v == NULL || PyList_Append(d, v) != 0) {
288 Py_XDECREF(v);
289 Py_DECREF(d);
Martin v. Löwise23c8682009-05-29 16:01:34 +0000290 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000291 return NULL;
292 }
293 Py_DECREF(v);
294 }
Fred Drake8e68eb62001-03-11 03:03:07 +0000295 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000296 return d;
Guido van Rossum20882d51994-06-23 11:15:44 +0000297}
298
Roger E. Masseb2b44e51996-12-18 19:37:32 +0000299static PyMethodDef grp_methods[] = {
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400300 GRP_GETGRGID_METHODDEF
301 GRP_GETGRNAM_METHODDEF
302 GRP_GETGRALL_METHODDEF
303 {NULL, NULL}
Guido van Rossum20882d51994-06-23 11:15:44 +0000304};
305
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000306PyDoc_STRVAR(grp__doc__,
Fred Drake51b6bc52000-07-08 16:56:26 +0000307"Access to the Unix group database.\n\
308\n\
309Group entries are reported as 4-tuples containing the following fields\n\
310from the group database, in order:\n\
311\n\
Georg Brandl41ea1f42014-10-02 08:34:41 +0200312 gr_name - name of the group\n\
313 gr_passwd - group password (encrypted); often empty\n\
314 gr_gid - numeric ID of the group\n\
315 gr_mem - list of members\n\
Fred Drake51b6bc52000-07-08 16:56:26 +0000316\n\
317The gid is an integer, name and password are strings. (Note that most\n\
318users are not explicitly listed as members of the groups they are in\n\
319according to the password database. Check both databases to get\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000320complete membership information.)");
Fred Drake51b6bc52000-07-08 16:56:26 +0000321
Dino Viehland40a53132019-09-10 11:30:36 +0100322static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) {
323 Py_VISIT(modulestate(m)->StructGrpType);
324 return 0;
325}
Fred Drake51b6bc52000-07-08 16:56:26 +0000326
Dino Viehland40a53132019-09-10 11:30:36 +0100327static int grpmodule_clear(PyObject *m) {
328 Py_CLEAR(modulestate(m)->StructGrpType);
329 return 0;
330}
331
332static void grpmodule_free(void *m) {
333 grpmodule_clear((PyObject *)m);
334}
Martin v. Löwis1a214512008-06-11 05:26:20 +0000335
336static struct PyModuleDef grpmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 PyModuleDef_HEAD_INIT,
338 "grp",
339 grp__doc__,
Dino Viehland40a53132019-09-10 11:30:36 +0100340 sizeof(grpmodulestate),
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 grp_methods,
342 NULL,
Dino Viehland40a53132019-09-10 11:30:36 +0100343 grpmodule_traverse,
344 grpmodule_clear,
345 grpmodule_free,
Martin v. Löwis1a214512008-06-11 05:26:20 +0000346};
347
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000348PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000349PyInit_grp(void)
Guido van Rossum20882d51994-06-23 11:15:44 +0000350{
Dino Viehland40a53132019-09-10 11:30:36 +0100351 PyObject *m;
352 if ((m = PyState_FindModule(&grpmodule)) != NULL) {
353 Py_INCREF(m);
354 return m;
Victor Stinner1c8f0592013-07-22 22:24:54 +0200355 }
Dino Viehland40a53132019-09-10 11:30:36 +0100356
357 if ((m = PyModule_Create(&grpmodule)) == NULL) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200358 return NULL;
Dino Viehland40a53132019-09-10 11:30:36 +0100359 }
360
361 grpmodulestate *state = PyModule_GetState(m);
362 state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc);
363 if (state->StructGrpType == NULL) {
364 return NULL;
365 }
366
367 Py_INCREF(state->StructGrpType);
368 PyModule_AddObject(m, "struct_group", (PyObject *) state->StructGrpType);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000369 return m;
Guido van Rossum20882d51994-06-23 11:15:44 +0000370}