blob: ab766b9850936dd9e7b292b157060cfc570aa893 [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
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000037static int initialized;
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000038static PyTypeObject StructGrpType;
Fred Drake51b6bc52000-07-08 16:56:26 +000039
William Grzybowski23e65b22018-09-07 09:06:15 -030040#define DEFAULT_BUFFER_SIZE 1024
41
Fred Drake51b6bc52000-07-08 16:56:26 +000042static PyObject *
43mkgrent(struct group *p)
Guido van Rossum20882d51994-06-23 11:15:44 +000044{
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000045 int setIndex = 0;
46 PyObject *v = PyStructSequence_New(&StructGrpType), *w;
Fred Drake51b6bc52000-07-08 16:56:26 +000047 char **member;
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000048
49 if (v == NULL)
50 return NULL;
51
Fred Drake51b6bc52000-07-08 16:56:26 +000052 if ((w = PyList_New(0)) == NULL) {
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000053 Py_DECREF(v);
Fred Drake51b6bc52000-07-08 16:56:26 +000054 return NULL;
55 }
56 for (member = p->gr_mem; *member != NULL; member++) {
Victor Stinner97c18ab2010-05-07 16:34:53 +000057 PyObject *x = PyUnicode_DecodeFSDefault(*member);
Fred Drake51b6bc52000-07-08 16:56:26 +000058 if (x == NULL || PyList_Append(w, x) != 0) {
59 Py_XDECREF(x);
60 Py_DECREF(w);
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000061 Py_DECREF(v);
Fred Drake51b6bc52000-07-08 16:56:26 +000062 return NULL;
63 }
64 Py_DECREF(x);
65 }
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000066
67#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
Victor Stinner97c18ab2010-05-07 16:34:53 +000068 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000069 if (p->gr_passwd)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000070 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
Martin v. Löwisceb7c182002-09-17 07:05:25 +000071 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000072 SET(setIndex++, Py_None);
73 Py_INCREF(Py_None);
Martin v. Löwisceb7c182002-09-17 07:05:25 +000074 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +020075 SET(setIndex++, _PyLong_FromGid(p->gr_gid));
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000076 SET(setIndex++, w);
77#undef SET
78
79 if (PyErr_Occurred()) {
80 Py_DECREF(v);
Martin v. Löwisdbd55b32002-03-01 10:38:44 +000081 return NULL;
82 }
83
Fred Drake51b6bc52000-07-08 16:56:26 +000084 return v;
Guido van Rossum20882d51994-06-23 11:15:44 +000085}
86
Brett Cannon8fb7bb22014-08-22 11:52:46 -040087/*[clinic input]
88grp.getgrgid
89
90 id: object
91
92Return the group database entry for the given numeric group ID.
93
94If id is not valid, raise KeyError.
95[clinic start generated code]*/
96
Fred Drake51b6bc52000-07-08 16:56:26 +000097static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +030098grp_getgrgid_impl(PyObject *module, PyObject *id)
99/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000100{
William Grzybowski23e65b22018-09-07 09:06:15 -0300101 PyObject *py_int_id, *retval = NULL;
102 int nomem = 0;
103 char *buf = NULL, *buf2 = NULL;
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200104 gid_t gid;
Fred Drake51b6bc52000-07-08 16:56:26 +0000105 struct group *p;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000106
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200107 if (!_Py_Gid_Converter(id, &gid)) {
108 if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000109 return NULL;
Serhiy Storchaka9cc4ed52016-01-18 18:49:57 +0200110 }
111 PyErr_Clear();
112 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
113 "group id must be int, not %.200",
114 id->ob_type->tp_name) < 0) {
115 return NULL;
116 }
117 py_int_id = PyNumber_Long(id);
118 if (!py_int_id)
119 return NULL;
120 if (!_Py_Gid_Converter(py_int_id, &gid)) {
121 Py_DECREF(py_int_id);
122 return NULL;
123 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200124 Py_DECREF(py_int_id);
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200125 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300126#ifdef HAVE_GETGRGID_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300127 int status;
128 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300129 /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300130 struct group grp;
Thomas Wouters477c8d52006-05-27 19:21:47 +0000131
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300132 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300133 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
134 if (bufsize == -1) {
135 bufsize = DEFAULT_BUFFER_SIZE;
136 }
137
138 while (1) {
139 buf2 = PyMem_RawRealloc(buf, bufsize);
140 if (buf2 == NULL) {
141 p = NULL;
142 nomem = 1;
143 break;
144 }
145 buf = buf2;
146 status = getgrgid_r(gid, &grp, buf, bufsize, &p);
147 if (status != 0) {
148 p = NULL;
149 }
150 if (p != NULL || status != ERANGE) {
151 break;
152 }
153 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
154 nomem = 1;
155 break;
156 }
157 bufsize <<= 1;
158 }
159
160 Py_END_ALLOW_THREADS
161#else
162 p = getgrgid(gid);
163#endif
164 if (p == NULL) {
165 PyMem_RawFree(buf);
166 if (nomem == 1) {
167 return PyErr_NoMemory();
168 }
Serhiy Storchaka7cf55992013-02-10 21:56:49 +0200169 PyObject *gid_obj = _PyLong_FromGid(gid);
170 if (gid_obj == NULL)
171 return NULL;
172 PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
173 Py_DECREF(gid_obj);
Fred Drake51b6bc52000-07-08 16:56:26 +0000174 return NULL;
175 }
William Grzybowski23e65b22018-09-07 09:06:15 -0300176 retval = mkgrent(p);
177#ifdef HAVE_GETGRGID_R
178 PyMem_RawFree(buf);
179#endif
180 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000181}
182
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400183/*[clinic input]
184grp.getgrnam
Thomas Wouters477c8d52006-05-27 19:21:47 +0000185
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400186 name: unicode
187
188Return the group database entry for the given group name.
189
190If name is not valid, raise KeyError.
191[clinic start generated code]*/
192
193static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300194grp_getgrnam_impl(PyObject *module, PyObject *name)
195/*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400196{
William Grzybowski23e65b22018-09-07 09:06:15 -0300197 char *buf = NULL, *buf2 = NULL, *name_chars;
198 int nomem = 0;
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400199 struct group *p;
200 PyObject *bytes, *retval = NULL;
201
202 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000203 return NULL;
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300204 /* check for embedded null bytes */
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400205 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000206 goto out;
William Grzybowski23e65b22018-09-07 09:06:15 -0300207#ifdef HAVE_GETGRNAM_R
William Grzybowski23e65b22018-09-07 09:06:15 -0300208 int status;
209 Py_ssize_t bufsize;
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300210 /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
William Grzybowski23e65b22018-09-07 09:06:15 -0300211 struct group grp;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212
Alexey Izbysheve359bc22018-11-04 18:44:16 +0300213 Py_BEGIN_ALLOW_THREADS
William Grzybowski23e65b22018-09-07 09:06:15 -0300214 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
215 if (bufsize == -1) {
216 bufsize = DEFAULT_BUFFER_SIZE;
217 }
218
219 while(1) {
220 buf2 = PyMem_RawRealloc(buf, bufsize);
221 if (buf2 == NULL) {
222 p = NULL;
223 nomem = 1;
224 break;
225 }
226 buf = buf2;
227 status = getgrnam_r(name_chars, &grp, buf, bufsize, &p);
228 if (status != 0) {
229 p = NULL;
230 }
231 if (p != NULL || status != ERANGE) {
232 break;
233 }
234 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
235 nomem = 1;
236 break;
237 }
238 bufsize <<= 1;
239 }
240
241 Py_END_ALLOW_THREADS
242#else
243 p = getgrnam(name_chars);
244#endif
245 if (p == NULL) {
246 if (nomem == 1) {
247 PyErr_NoMemory();
248 }
249 else {
William Grzybowski34c7f0c2018-12-05 17:10:18 -0200250 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
William Grzybowski23e65b22018-09-07 09:06:15 -0300251 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000252 goto out;
Fred Drake51b6bc52000-07-08 16:56:26 +0000253 }
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000254 retval = mkgrent(p);
255out:
William Grzybowski23e65b22018-09-07 09:06:15 -0300256 PyMem_RawFree(buf);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000257 Py_DECREF(bytes);
258 return retval;
Guido van Rossum20882d51994-06-23 11:15:44 +0000259}
260
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400261/*[clinic input]
262grp.getgrall
263
264Return a list of all available group entries, in arbitrary order.
265
266An entry whose name starts with '+' or '-' represents an instruction
267to use YP/NIS and may not be accessible via getgrnam or getgrgid.
268[clinic start generated code]*/
269
Fred Drake51b6bc52000-07-08 16:56:26 +0000270static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300271grp_getgrall_impl(PyObject *module)
272/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
Guido van Rossum20882d51994-06-23 11:15:44 +0000273{
Fred Drake51b6bc52000-07-08 16:56:26 +0000274 PyObject *d;
275 struct group *p;
276
Fred Drake51b6bc52000-07-08 16:56:26 +0000277 if ((d = PyList_New(0)) == NULL)
278 return NULL;
279 setgrent();
280 while ((p = getgrent()) != NULL) {
281 PyObject *v = mkgrent(p);
282 if (v == NULL || PyList_Append(d, v) != 0) {
283 Py_XDECREF(v);
284 Py_DECREF(d);
Martin v. Löwise23c8682009-05-29 16:01:34 +0000285 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000286 return NULL;
287 }
288 Py_DECREF(v);
289 }
Fred Drake8e68eb62001-03-11 03:03:07 +0000290 endgrent();
Fred Drake51b6bc52000-07-08 16:56:26 +0000291 return d;
Guido van Rossum20882d51994-06-23 11:15:44 +0000292}
293
Roger E. Masseb2b44e51996-12-18 19:37:32 +0000294static PyMethodDef grp_methods[] = {
Brett Cannon8fb7bb22014-08-22 11:52:46 -0400295 GRP_GETGRGID_METHODDEF
296 GRP_GETGRNAM_METHODDEF
297 GRP_GETGRALL_METHODDEF
298 {NULL, NULL}
Guido van Rossum20882d51994-06-23 11:15:44 +0000299};
300
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000301PyDoc_STRVAR(grp__doc__,
Fred Drake51b6bc52000-07-08 16:56:26 +0000302"Access to the Unix group database.\n\
303\n\
304Group entries are reported as 4-tuples containing the following fields\n\
305from the group database, in order:\n\
306\n\
Georg Brandl41ea1f42014-10-02 08:34:41 +0200307 gr_name - name of the group\n\
308 gr_passwd - group password (encrypted); often empty\n\
309 gr_gid - numeric ID of the group\n\
310 gr_mem - list of members\n\
Fred Drake51b6bc52000-07-08 16:56:26 +0000311\n\
312The gid is an integer, name and password are strings. (Note that most\n\
313users are not explicitly listed as members of the groups they are in\n\
314according to the password database. Check both databases to get\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000315complete membership information.)");
Fred Drake51b6bc52000-07-08 16:56:26 +0000316
317
Martin v. Löwis1a214512008-06-11 05:26:20 +0000318
319static struct PyModuleDef grpmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 PyModuleDef_HEAD_INIT,
321 "grp",
322 grp__doc__,
323 -1,
324 grp_methods,
325 NULL,
326 NULL,
327 NULL,
328 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000329};
330
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000331PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000332PyInit_grp(void)
Guido van Rossum20882d51994-06-23 11:15:44 +0000333{
Martin v. Löwisdbd55b32002-03-01 10:38:44 +0000334 PyObject *m, *d;
Martin v. Löwis1a214512008-06-11 05:26:20 +0000335 m = PyModule_Create(&grpmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +0000336 if (m == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +0000337 return NULL;
Martin v. Löwisdbd55b32002-03-01 10:38:44 +0000338 d = PyModule_GetDict(m);
Victor Stinner1c8f0592013-07-22 22:24:54 +0200339 if (!initialized) {
340 if (PyStructSequence_InitType2(&StructGrpType,
341 &struct_group_type_desc) < 0)
342 return NULL;
343 }
344 if (PyDict_SetItemString(d, "struct_group",
345 (PyObject *)&StructGrpType) < 0)
346 return NULL;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000347 initialized = 1;
Martin v. Löwis1a214512008-06-11 05:26:20 +0000348 return m;
Guido van Rossum20882d51994-06-23 11:15:44 +0000349}