• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* UNIX group file access module */
3 
4 #include "Python.h"
5 #include "posixmodule.h"
6 
7 #include <grp.h>
8 
9 #include "clinic/grpmodule.c.h"
10 /*[clinic input]
11 module grp
12 [clinic start generated code]*/
13 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=cade63f2ed1bd9f8]*/
14 
15 static PyStructSequence_Field struct_group_type_fields[] = {
16    {"gr_name", "group name"},
17    {"gr_passwd", "password"},
18    {"gr_gid", "group id"},
19    {"gr_mem", "group members"},
20    {0}
21 };
22 
23 PyDoc_STRVAR(struct_group__doc__,
24 "grp.struct_group: Results from getgr*() routines.\n\n\
25 This object may be accessed either as a tuple of\n\
26   (gr_name,gr_passwd,gr_gid,gr_mem)\n\
27 or via the object attributes as named in the above tuple.\n");
28 
29 static PyStructSequence_Desc struct_group_type_desc = {
30    "grp.struct_group",
31    struct_group__doc__,
32    struct_group_type_fields,
33    4,
34 };
35 
36 
37 static int initialized;
38 static PyTypeObject StructGrpType;
39 
40 #define DEFAULT_BUFFER_SIZE 1024
41 
42 static PyObject *
mkgrent(struct group * p)43 mkgrent(struct group *p)
44 {
45     int setIndex = 0;
46     PyObject *v = PyStructSequence_New(&StructGrpType), *w;
47     char **member;
48 
49     if (v == NULL)
50         return NULL;
51 
52     if ((w = PyList_New(0)) == NULL) {
53         Py_DECREF(v);
54         return NULL;
55     }
56     for (member = p->gr_mem; *member != NULL; member++) {
57         PyObject *x = PyUnicode_DecodeFSDefault(*member);
58         if (x == NULL || PyList_Append(w, x) != 0) {
59             Py_XDECREF(x);
60             Py_DECREF(w);
61             Py_DECREF(v);
62             return NULL;
63         }
64         Py_DECREF(x);
65     }
66 
67 #define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
68     SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
69     if (p->gr_passwd)
70             SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
71     else {
72             SET(setIndex++, Py_None);
73             Py_INCREF(Py_None);
74     }
75     SET(setIndex++, _PyLong_FromGid(p->gr_gid));
76     SET(setIndex++, w);
77 #undef SET
78 
79     if (PyErr_Occurred()) {
80         Py_DECREF(v);
81         return NULL;
82     }
83 
84     return v;
85 }
86 
87 /*[clinic input]
88 grp.getgrgid
89 
90     id: object
91 
92 Return the group database entry for the given numeric group ID.
93 
94 If id is not valid, raise KeyError.
95 [clinic start generated code]*/
96 
97 static PyObject *
grp_getgrgid_impl(PyObject * module,PyObject * id)98 grp_getgrgid_impl(PyObject *module, PyObject *id)
99 /*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
100 {
101     PyObject *py_int_id, *retval = NULL;
102     int nomem = 0;
103     char *buf = NULL, *buf2 = NULL;
104     gid_t gid;
105     struct group *p;
106 
107     if (!_Py_Gid_Converter(id, &gid)) {
108         if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
109             return NULL;
110         }
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         }
124         Py_DECREF(py_int_id);
125     }
126 #ifdef HAVE_GETGRGID_R
127     int status;
128     Py_ssize_t bufsize;
129     /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */
130     struct group grp;
131 
132     Py_BEGIN_ALLOW_THREADS
133     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         }
169         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);
174         return NULL;
175     }
176     retval = mkgrent(p);
177 #ifdef HAVE_GETGRGID_R
178     PyMem_RawFree(buf);
179 #endif
180     return retval;
181 }
182 
183 /*[clinic input]
184 grp.getgrnam
185 
186     name: unicode
187 
188 Return the group database entry for the given group name.
189 
190 If name is not valid, raise KeyError.
191 [clinic start generated code]*/
192 
193 static PyObject *
grp_getgrnam_impl(PyObject * module,PyObject * name)194 grp_getgrnam_impl(PyObject *module, PyObject *name)
195 /*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
196 {
197     char *buf = NULL, *buf2 = NULL, *name_chars;
198     int nomem = 0;
199     struct group *p;
200     PyObject *bytes, *retval = NULL;
201 
202     if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
203         return NULL;
204     /* check for embedded null bytes */
205     if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
206         goto out;
207 #ifdef HAVE_GETGRNAM_R
208     int status;
209     Py_ssize_t bufsize;
210     /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */
211     struct group grp;
212 
213     Py_BEGIN_ALLOW_THREADS
214     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 {
250             PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
251         }
252         goto out;
253     }
254     retval = mkgrent(p);
255 out:
256     PyMem_RawFree(buf);
257     Py_DECREF(bytes);
258     return retval;
259 }
260 
261 /*[clinic input]
262 grp.getgrall
263 
264 Return a list of all available group entries, in arbitrary order.
265 
266 An entry whose name starts with '+' or '-' represents an instruction
267 to use YP/NIS and may not be accessible via getgrnam or getgrgid.
268 [clinic start generated code]*/
269 
270 static PyObject *
grp_getgrall_impl(PyObject * module)271 grp_getgrall_impl(PyObject *module)
272 /*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
273 {
274     PyObject *d;
275     struct group *p;
276 
277     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);
285             endgrent();
286             return NULL;
287         }
288         Py_DECREF(v);
289     }
290     endgrent();
291     return d;
292 }
293 
294 static PyMethodDef grp_methods[] = {
295     GRP_GETGRGID_METHODDEF
296     GRP_GETGRNAM_METHODDEF
297     GRP_GETGRALL_METHODDEF
298     {NULL, NULL}
299 };
300 
301 PyDoc_STRVAR(grp__doc__,
302 "Access to the Unix group database.\n\
303 \n\
304 Group entries are reported as 4-tuples containing the following fields\n\
305 from the group database, in order:\n\
306 \n\
307   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\
311 \n\
312 The gid is an integer, name and password are strings.  (Note that most\n\
313 users are not explicitly listed as members of the groups they are in\n\
314 according to the password database.  Check both databases to get\n\
315 complete membership information.)");
316 
317 
318 
319 static struct PyModuleDef grpmodule = {
320         PyModuleDef_HEAD_INIT,
321         "grp",
322         grp__doc__,
323         -1,
324         grp_methods,
325         NULL,
326         NULL,
327         NULL,
328         NULL
329 };
330 
331 PyMODINIT_FUNC
PyInit_grp(void)332 PyInit_grp(void)
333 {
334     PyObject *m, *d;
335     m = PyModule_Create(&grpmodule);
336     if (m == NULL)
337         return NULL;
338     d = PyModule_GetDict(m);
339     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;
347     initialized = 1;
348     return m;
349 }
350