/src/Python-3.8.3/Modules/pwdmodule.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* UNIX password file access module */ |
3 | | |
4 | | #include "Python.h" |
5 | | #include "posixmodule.h" |
6 | | |
7 | | #include <pwd.h> |
8 | | |
9 | | #include "clinic/pwdmodule.c.h" |
10 | | /*[clinic input] |
11 | | module pwd |
12 | | [clinic start generated code]*/ |
13 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=60f628ef356b97b6]*/ |
14 | | |
15 | | static PyStructSequence_Field struct_pwd_type_fields[] = { |
16 | | {"pw_name", "user name"}, |
17 | | {"pw_passwd", "password"}, |
18 | | {"pw_uid", "user id"}, |
19 | | {"pw_gid", "group id"}, |
20 | | {"pw_gecos", "real name"}, |
21 | | {"pw_dir", "home directory"}, |
22 | | {"pw_shell", "shell program"}, |
23 | | {0} |
24 | | }; |
25 | | |
26 | | PyDoc_STRVAR(struct_passwd__doc__, |
27 | | "pwd.struct_passwd: Results from getpw*() routines.\n\n\ |
28 | | This object may be accessed either as a tuple of\n\ |
29 | | (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell)\n\ |
30 | | or via the object attributes as named in the above tuple."); |
31 | | |
32 | | static PyStructSequence_Desc struct_pwd_type_desc = { |
33 | | "pwd.struct_passwd", |
34 | | struct_passwd__doc__, |
35 | | struct_pwd_type_fields, |
36 | | 7, |
37 | | }; |
38 | | |
39 | | PyDoc_STRVAR(pwd__doc__, |
40 | | "This module provides access to the Unix password database.\n\ |
41 | | It is available on all Unix versions.\n\ |
42 | | \n\ |
43 | | Password database entries are reported as 7-tuples containing the following\n\ |
44 | | items from the password database (see `<pwd.h>'), in order:\n\ |
45 | | pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell.\n\ |
46 | | The uid and gid items are integers, all others are strings. An\n\ |
47 | | exception is raised if the entry asked for cannot be found."); |
48 | | |
49 | | |
50 | | static int initialized; |
51 | | static PyTypeObject StructPwdType; |
52 | | |
53 | 0 | #define DEFAULT_BUFFER_SIZE 1024 |
54 | | |
55 | | static void |
56 | | sets(PyObject *v, int i, const char* val) |
57 | 0 | { |
58 | 0 | if (val) { |
59 | 0 | PyObject *o = PyUnicode_DecodeFSDefault(val); |
60 | 0 | PyStructSequence_SET_ITEM(v, i, o); |
61 | 0 | } |
62 | 0 | else { |
63 | 0 | PyStructSequence_SET_ITEM(v, i, Py_None); |
64 | 0 | Py_INCREF(Py_None); |
65 | 0 | } |
66 | 0 | } |
67 | | |
68 | | static PyObject * |
69 | | mkpwent(struct passwd *p) |
70 | 0 | { |
71 | 0 | int setIndex = 0; |
72 | 0 | PyObject *v = PyStructSequence_New(&StructPwdType); |
73 | 0 | if (v == NULL) |
74 | 0 | return NULL; |
75 | | |
76 | 0 | #define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val)) |
77 | 0 | #define SETS(i,val) sets(v, i, val) |
78 | | |
79 | 0 | SETS(setIndex++, p->pw_name); |
80 | 0 | #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__) |
81 | 0 | SETS(setIndex++, p->pw_passwd); |
82 | | #else |
83 | | SETS(setIndex++, ""); |
84 | | #endif |
85 | 0 | PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid)); |
86 | 0 | PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid)); |
87 | 0 | #if defined(HAVE_STRUCT_PASSWD_PW_GECOS) |
88 | 0 | SETS(setIndex++, p->pw_gecos); |
89 | | #else |
90 | | SETS(setIndex++, ""); |
91 | | #endif |
92 | 0 | SETS(setIndex++, p->pw_dir); |
93 | 0 | SETS(setIndex++, p->pw_shell); |
94 | |
|
95 | 0 | #undef SETS |
96 | 0 | #undef SETI |
97 | |
|
98 | 0 | if (PyErr_Occurred()) { |
99 | 0 | Py_XDECREF(v); |
100 | 0 | return NULL; |
101 | 0 | } |
102 | | |
103 | 0 | return v; |
104 | 0 | } |
105 | | |
106 | | /*[clinic input] |
107 | | pwd.getpwuid |
108 | | |
109 | | uidobj: object |
110 | | / |
111 | | |
112 | | Return the password database entry for the given numeric user ID. |
113 | | |
114 | | See `help(pwd)` for more on password database entries. |
115 | | [clinic start generated code]*/ |
116 | | |
117 | | static PyObject * |
118 | | pwd_getpwuid(PyObject *module, PyObject *uidobj) |
119 | | /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/ |
120 | 0 | { |
121 | 0 | PyObject *retval = NULL; |
122 | 0 | uid_t uid; |
123 | 0 | int nomem = 0; |
124 | 0 | struct passwd *p; |
125 | 0 | char *buf = NULL, *buf2 = NULL; |
126 | |
|
127 | 0 | if (!_Py_Uid_Converter(uidobj, &uid)) { |
128 | 0 | if (PyErr_ExceptionMatches(PyExc_OverflowError)) |
129 | 0 | PyErr_Format(PyExc_KeyError, |
130 | 0 | "getpwuid(): uid not found"); |
131 | 0 | return NULL; |
132 | 0 | } |
133 | 0 | #ifdef HAVE_GETPWUID_R |
134 | 0 | int status; |
135 | 0 | Py_ssize_t bufsize; |
136 | | /* Note: 'pwd' will be used via pointer 'p' on getpwuid_r success. */ |
137 | 0 | struct passwd pwd; |
138 | |
|
139 | 0 | Py_BEGIN_ALLOW_THREADS |
140 | 0 | bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); |
141 | 0 | if (bufsize == -1) { |
142 | 0 | bufsize = DEFAULT_BUFFER_SIZE; |
143 | 0 | } |
144 | |
|
145 | 0 | while(1) { |
146 | 0 | buf2 = PyMem_RawRealloc(buf, bufsize); |
147 | 0 | if (buf2 == NULL) { |
148 | 0 | p = NULL; |
149 | 0 | nomem = 1; |
150 | 0 | break; |
151 | 0 | } |
152 | 0 | buf = buf2; |
153 | 0 | status = getpwuid_r(uid, &pwd, buf, bufsize, &p); |
154 | 0 | if (status != 0) { |
155 | 0 | p = NULL; |
156 | 0 | } |
157 | 0 | if (p != NULL || status != ERANGE) { |
158 | 0 | break; |
159 | 0 | } |
160 | 0 | if (bufsize > (PY_SSIZE_T_MAX >> 1)) { |
161 | 0 | nomem = 1; |
162 | 0 | break; |
163 | 0 | } |
164 | 0 | bufsize <<= 1; |
165 | 0 | } |
166 | |
|
167 | 0 | Py_END_ALLOW_THREADS |
168 | | #else |
169 | | p = getpwuid(uid); |
170 | | #endif |
171 | 0 | if (p == NULL) { |
172 | 0 | PyMem_RawFree(buf); |
173 | 0 | if (nomem == 1) { |
174 | 0 | return PyErr_NoMemory(); |
175 | 0 | } |
176 | 0 | PyObject *uid_obj = _PyLong_FromUid(uid); |
177 | 0 | if (uid_obj == NULL) |
178 | 0 | return NULL; |
179 | 0 | PyErr_Format(PyExc_KeyError, |
180 | 0 | "getpwuid(): uid not found: %S", uid_obj); |
181 | 0 | Py_DECREF(uid_obj); |
182 | 0 | return NULL; |
183 | 0 | } |
184 | 0 | retval = mkpwent(p); |
185 | 0 | #ifdef HAVE_GETPWUID_R |
186 | 0 | PyMem_RawFree(buf); |
187 | 0 | #endif |
188 | 0 | return retval; |
189 | 0 | } |
190 | | |
191 | | /*[clinic input] |
192 | | pwd.getpwnam |
193 | | |
194 | | name: unicode |
195 | | / |
196 | | |
197 | | Return the password database entry for the given user name. |
198 | | |
199 | | See `help(pwd)` for more on password database entries. |
200 | | [clinic start generated code]*/ |
201 | | |
202 | | static PyObject * |
203 | | pwd_getpwnam_impl(PyObject *module, PyObject *name) |
204 | | /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/ |
205 | 0 | { |
206 | 0 | char *buf = NULL, *buf2 = NULL, *name_chars; |
207 | 0 | int nomem = 0; |
208 | 0 | struct passwd *p; |
209 | 0 | PyObject *bytes, *retval = NULL; |
210 | |
|
211 | 0 | if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL) |
212 | 0 | return NULL; |
213 | | /* check for embedded null bytes */ |
214 | 0 | if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1) |
215 | 0 | goto out; |
216 | 0 | #ifdef HAVE_GETPWNAM_R |
217 | 0 | int status; |
218 | 0 | Py_ssize_t bufsize; |
219 | | /* Note: 'pwd' will be used via pointer 'p' on getpwnam_r success. */ |
220 | 0 | struct passwd pwd; |
221 | |
|
222 | 0 | Py_BEGIN_ALLOW_THREADS |
223 | 0 | bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); |
224 | 0 | if (bufsize == -1) { |
225 | 0 | bufsize = DEFAULT_BUFFER_SIZE; |
226 | 0 | } |
227 | |
|
228 | 0 | while(1) { |
229 | 0 | buf2 = PyMem_RawRealloc(buf, bufsize); |
230 | 0 | if (buf2 == NULL) { |
231 | 0 | p = NULL; |
232 | 0 | nomem = 1; |
233 | 0 | break; |
234 | 0 | } |
235 | 0 | buf = buf2; |
236 | 0 | status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p); |
237 | 0 | if (status != 0) { |
238 | 0 | p = NULL; |
239 | 0 | } |
240 | 0 | if (p != NULL || status != ERANGE) { |
241 | 0 | break; |
242 | 0 | } |
243 | 0 | if (bufsize > (PY_SSIZE_T_MAX >> 1)) { |
244 | 0 | nomem = 1; |
245 | 0 | break; |
246 | 0 | } |
247 | 0 | bufsize <<= 1; |
248 | 0 | } |
249 | |
|
250 | 0 | Py_END_ALLOW_THREADS |
251 | | #else |
252 | | p = getpwnam(name_chars); |
253 | | #endif |
254 | 0 | if (p == NULL) { |
255 | 0 | if (nomem == 1) { |
256 | 0 | PyErr_NoMemory(); |
257 | 0 | } |
258 | 0 | else { |
259 | 0 | PyErr_Format(PyExc_KeyError, |
260 | 0 | "getpwnam(): name not found: %R", name); |
261 | 0 | } |
262 | 0 | goto out; |
263 | 0 | } |
264 | 0 | retval = mkpwent(p); |
265 | 0 | out: |
266 | 0 | PyMem_RawFree(buf); |
267 | 0 | Py_DECREF(bytes); |
268 | 0 | return retval; |
269 | 0 | } |
270 | | |
271 | | #ifdef HAVE_GETPWENT |
272 | | /*[clinic input] |
273 | | pwd.getpwall |
274 | | |
275 | | Return a list of all available password database entries, in arbitrary order. |
276 | | |
277 | | See help(pwd) for more on password database entries. |
278 | | [clinic start generated code]*/ |
279 | | |
280 | | static PyObject * |
281 | | pwd_getpwall_impl(PyObject *module) |
282 | | /*[clinic end generated code: output=4853d2f5a0afac8a input=d7ecebfd90219b85]*/ |
283 | 0 | { |
284 | 0 | PyObject *d; |
285 | 0 | struct passwd *p; |
286 | 0 | if ((d = PyList_New(0)) == NULL) |
287 | 0 | return NULL; |
288 | 0 | setpwent(); |
289 | 0 | while ((p = getpwent()) != NULL) { |
290 | 0 | PyObject *v = mkpwent(p); |
291 | 0 | if (v == NULL || PyList_Append(d, v) != 0) { |
292 | 0 | Py_XDECREF(v); |
293 | 0 | Py_DECREF(d); |
294 | 0 | endpwent(); |
295 | 0 | return NULL; |
296 | 0 | } |
297 | 0 | Py_DECREF(v); |
298 | 0 | } |
299 | 0 | endpwent(); |
300 | 0 | return d; |
301 | 0 | } |
302 | | #endif |
303 | | |
304 | | static PyMethodDef pwd_methods[] = { |
305 | | PWD_GETPWUID_METHODDEF |
306 | | PWD_GETPWNAM_METHODDEF |
307 | | #ifdef HAVE_GETPWENT |
308 | | PWD_GETPWALL_METHODDEF |
309 | | #endif |
310 | | {NULL, NULL} /* sentinel */ |
311 | | }; |
312 | | |
313 | | static struct PyModuleDef pwdmodule = { |
314 | | PyModuleDef_HEAD_INIT, |
315 | | "pwd", |
316 | | pwd__doc__, |
317 | | -1, |
318 | | pwd_methods, |
319 | | NULL, |
320 | | NULL, |
321 | | NULL, |
322 | | NULL |
323 | | }; |
324 | | |
325 | | |
326 | | PyMODINIT_FUNC |
327 | | PyInit_pwd(void) |
328 | 0 | { |
329 | 0 | PyObject *m; |
330 | 0 | m = PyModule_Create(&pwdmodule); |
331 | 0 | if (m == NULL) |
332 | 0 | return NULL; |
333 | | |
334 | 0 | if (!initialized) { |
335 | 0 | if (PyStructSequence_InitType2(&StructPwdType, |
336 | 0 | &struct_pwd_type_desc) < 0) |
337 | 0 | return NULL; |
338 | 0 | initialized = 1; |
339 | 0 | } |
340 | 0 | Py_INCREF((PyObject *) &StructPwdType); |
341 | 0 | PyModule_AddObject(m, "struct_passwd", (PyObject *) &StructPwdType); |
342 | 0 | return m; |
343 | 0 | } |