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 static PyObject *
mkgrent(struct group * p)41 mkgrent(struct group *p)
42 {
43 int setIndex = 0;
44 PyObject *v = PyStructSequence_New(&StructGrpType), *w;
45 char **member;
46
47 if (v == NULL)
48 return NULL;
49
50 if ((w = PyList_New(0)) == NULL) {
51 Py_DECREF(v);
52 return NULL;
53 }
54 for (member = p->gr_mem; *member != NULL; member++) {
55 PyObject *x = PyUnicode_DecodeFSDefault(*member);
56 if (x == NULL || PyList_Append(w, x) != 0) {
57 Py_XDECREF(x);
58 Py_DECREF(w);
59 Py_DECREF(v);
60 return NULL;
61 }
62 Py_DECREF(x);
63 }
64
65 #define SET(i,val) PyStructSequence_SET_ITEM(v, i, val)
66 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name));
67 if (p->gr_passwd)
68 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd));
69 else {
70 SET(setIndex++, Py_None);
71 Py_INCREF(Py_None);
72 }
73 SET(setIndex++, _PyLong_FromGid(p->gr_gid));
74 SET(setIndex++, w);
75 #undef SET
76
77 if (PyErr_Occurred()) {
78 Py_DECREF(v);
79 return NULL;
80 }
81
82 return v;
83 }
84
85 /*[clinic input]
86 grp.getgrgid
87
88 id: object
89
90 Return the group database entry for the given numeric group ID.
91
92 If id is not valid, raise KeyError.
93 [clinic start generated code]*/
94
95 static PyObject *
grp_getgrgid_impl(PyObject * module,PyObject * id)96 grp_getgrgid_impl(PyObject *module, PyObject *id)
97 /*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/
98 {
99 PyObject *py_int_id;
100 gid_t gid;
101 struct group *p;
102
103 if (!_Py_Gid_Converter(id, &gid)) {
104 if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
105 return NULL;
106 }
107 PyErr_Clear();
108 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
109 "group id must be int, not %.200",
110 id->ob_type->tp_name) < 0) {
111 return NULL;
112 }
113 py_int_id = PyNumber_Long(id);
114 if (!py_int_id)
115 return NULL;
116 if (!_Py_Gid_Converter(py_int_id, &gid)) {
117 Py_DECREF(py_int_id);
118 return NULL;
119 }
120 Py_DECREF(py_int_id);
121 }
122
123 if ((p = getgrgid(gid)) == NULL) {
124 PyObject *gid_obj = _PyLong_FromGid(gid);
125 if (gid_obj == NULL)
126 return NULL;
127 PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj);
128 Py_DECREF(gid_obj);
129 return NULL;
130 }
131 return mkgrent(p);
132 }
133
134 /*[clinic input]
135 grp.getgrnam
136
137 name: unicode
138
139 Return the group database entry for the given group name.
140
141 If name is not valid, raise KeyError.
142 [clinic start generated code]*/
143
144 static PyObject *
grp_getgrnam_impl(PyObject * module,PyObject * name)145 grp_getgrnam_impl(PyObject *module, PyObject *name)
146 /*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/
147 {
148 char *name_chars;
149 struct group *p;
150 PyObject *bytes, *retval = NULL;
151
152 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
153 return NULL;
154 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
155 goto out;
156
157 if ((p = getgrnam(name_chars)) == NULL) {
158 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %s", name_chars);
159 goto out;
160 }
161 retval = mkgrent(p);
162 out:
163 Py_DECREF(bytes);
164 return retval;
165 }
166
167 /*[clinic input]
168 grp.getgrall
169
170 Return a list of all available group entries, in arbitrary order.
171
172 An entry whose name starts with '+' or '-' represents an instruction
173 to use YP/NIS and may not be accessible via getgrnam or getgrgid.
174 [clinic start generated code]*/
175
176 static PyObject *
grp_getgrall_impl(PyObject * module)177 grp_getgrall_impl(PyObject *module)
178 /*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
179 {
180 PyObject *d;
181 struct group *p;
182
183 if ((d = PyList_New(0)) == NULL)
184 return NULL;
185 setgrent();
186 while ((p = getgrent()) != NULL) {
187 PyObject *v = mkgrent(p);
188 if (v == NULL || PyList_Append(d, v) != 0) {
189 Py_XDECREF(v);
190 Py_DECREF(d);
191 endgrent();
192 return NULL;
193 }
194 Py_DECREF(v);
195 }
196 endgrent();
197 return d;
198 }
199
200 static PyMethodDef grp_methods[] = {
201 GRP_GETGRGID_METHODDEF
202 GRP_GETGRNAM_METHODDEF
203 GRP_GETGRALL_METHODDEF
204 {NULL, NULL}
205 };
206
207 PyDoc_STRVAR(grp__doc__,
208 "Access to the Unix group database.\n\
209 \n\
210 Group entries are reported as 4-tuples containing the following fields\n\
211 from the group database, in order:\n\
212 \n\
213 gr_name - name of the group\n\
214 gr_passwd - group password (encrypted); often empty\n\
215 gr_gid - numeric ID of the group\n\
216 gr_mem - list of members\n\
217 \n\
218 The gid is an integer, name and password are strings. (Note that most\n\
219 users are not explicitly listed as members of the groups they are in\n\
220 according to the password database. Check both databases to get\n\
221 complete membership information.)");
222
223
224
225 static struct PyModuleDef grpmodule = {
226 PyModuleDef_HEAD_INIT,
227 "grp",
228 grp__doc__,
229 -1,
230 grp_methods,
231 NULL,
232 NULL,
233 NULL,
234 NULL
235 };
236
237 PyMODINIT_FUNC
PyInit_grp(void)238 PyInit_grp(void)
239 {
240 PyObject *m, *d;
241 m = PyModule_Create(&grpmodule);
242 if (m == NULL)
243 return NULL;
244 d = PyModule_GetDict(m);
245 if (!initialized) {
246 if (PyStructSequence_InitType2(&StructGrpType,
247 &struct_group_type_desc) < 0)
248 return NULL;
249 }
250 if (PyDict_SetItemString(d, "struct_group",
251 (PyObject *)&StructGrpType) < 0)
252 return NULL;
253 initialized = 1;
254 return m;
255 }
256