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 | typedef struct { |
51 | PyTypeObject *StructPwdType; |
52 | } pwdmodulestate; |
53 | |
54 | static inline pwdmodulestate* |
55 | get_pwd_state(PyObject *module) |
56 | { |
57 | void *state = PyModule_GetState(module); |
58 | assert(state != NULL); |
59 | return (pwdmodulestate *)state; |
60 | } |
61 | |
62 | static struct PyModuleDef pwdmodule; |
63 | |
64 | #define DEFAULT_BUFFER_SIZE 1024 |
65 | |
66 | static void |
67 | sets(PyObject *v, int i, const char* val) |
68 | { |
69 | if (val) { |
70 | PyObject *o = PyUnicode_DecodeFSDefault(val); |
71 | PyStructSequence_SET_ITEM(v, i, o); |
72 | } |
73 | else { |
74 | PyStructSequence_SET_ITEM(v, i, Py_None); |
75 | Py_INCREF(Py_None); |
76 | } |
77 | } |
78 | |
79 | static PyObject * |
80 | mkpwent(PyObject *module, struct passwd *p) |
81 | { |
82 | int setIndex = 0; |
83 | PyObject *v = PyStructSequence_New(get_pwd_state(module)->StructPwdType); |
84 | if (v == NULL) |
85 | return NULL; |
86 | |
87 | #define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val)) |
88 | #define SETS(i,val) sets(v, i, val) |
89 | |
90 | SETS(setIndex++, p->pw_name); |
91 | #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__) |
92 | SETS(setIndex++, p->pw_passwd); |
93 | #else |
94 | SETS(setIndex++, "" ); |
95 | #endif |
96 | PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid)); |
97 | PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid)); |
98 | #if defined(HAVE_STRUCT_PASSWD_PW_GECOS) |
99 | SETS(setIndex++, p->pw_gecos); |
100 | #else |
101 | SETS(setIndex++, "" ); |
102 | #endif |
103 | SETS(setIndex++, p->pw_dir); |
104 | SETS(setIndex++, p->pw_shell); |
105 | |
106 | #undef SETS |
107 | #undef SETI |
108 | |
109 | if (PyErr_Occurred()) { |
110 | Py_XDECREF(v); |
111 | return NULL; |
112 | } |
113 | |
114 | return v; |
115 | } |
116 | |
117 | /*[clinic input] |
118 | pwd.getpwuid |
119 | |
120 | uidobj: object |
121 | / |
122 | |
123 | Return the password database entry for the given numeric user ID. |
124 | |
125 | See `help(pwd)` for more on password database entries. |
126 | [clinic start generated code]*/ |
127 | |
128 | static PyObject * |
129 | pwd_getpwuid(PyObject *module, PyObject *uidobj) |
130 | /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/ |
131 | { |
132 | PyObject *retval = NULL; |
133 | uid_t uid; |
134 | int nomem = 0; |
135 | struct passwd *p; |
136 | char *buf = NULL, *buf2 = NULL; |
137 | |
138 | if (!_Py_Uid_Converter(uidobj, &uid)) { |
139 | if (PyErr_ExceptionMatches(PyExc_OverflowError)) |
140 | PyErr_Format(PyExc_KeyError, |
141 | "getpwuid(): uid not found" ); |
142 | return NULL; |
143 | } |
144 | #ifdef HAVE_GETPWUID_R |
145 | int status; |
146 | Py_ssize_t bufsize; |
147 | /* Note: 'pwd' will be used via pointer 'p' on getpwuid_r success. */ |
148 | struct passwd pwd; |
149 | |
150 | Py_BEGIN_ALLOW_THREADS |
151 | bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); |
152 | if (bufsize == -1) { |
153 | bufsize = DEFAULT_BUFFER_SIZE; |
154 | } |
155 | |
156 | while(1) { |
157 | buf2 = PyMem_RawRealloc(buf, bufsize); |
158 | if (buf2 == NULL) { |
159 | p = NULL; |
160 | nomem = 1; |
161 | break; |
162 | } |
163 | buf = buf2; |
164 | status = getpwuid_r(uid, &pwd, buf, bufsize, &p); |
165 | if (status != 0) { |
166 | p = NULL; |
167 | } |
168 | if (p != NULL || status != ERANGE) { |
169 | break; |
170 | } |
171 | if (bufsize > (PY_SSIZE_T_MAX >> 1)) { |
172 | nomem = 1; |
173 | break; |
174 | } |
175 | bufsize <<= 1; |
176 | } |
177 | |
178 | Py_END_ALLOW_THREADS |
179 | #else |
180 | p = getpwuid(uid); |
181 | #endif |
182 | if (p == NULL) { |
183 | PyMem_RawFree(buf); |
184 | if (nomem == 1) { |
185 | return PyErr_NoMemory(); |
186 | } |
187 | PyObject *uid_obj = _PyLong_FromUid(uid); |
188 | if (uid_obj == NULL) |
189 | return NULL; |
190 | PyErr_Format(PyExc_KeyError, |
191 | "getpwuid(): uid not found: %S" , uid_obj); |
192 | Py_DECREF(uid_obj); |
193 | return NULL; |
194 | } |
195 | retval = mkpwent(module, p); |
196 | #ifdef HAVE_GETPWUID_R |
197 | PyMem_RawFree(buf); |
198 | #endif |
199 | return retval; |
200 | } |
201 | |
202 | /*[clinic input] |
203 | pwd.getpwnam |
204 | |
205 | name: unicode |
206 | / |
207 | |
208 | Return the password database entry for the given user name. |
209 | |
210 | See `help(pwd)` for more on password database entries. |
211 | [clinic start generated code]*/ |
212 | |
213 | static PyObject * |
214 | pwd_getpwnam_impl(PyObject *module, PyObject *name) |
215 | /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/ |
216 | { |
217 | char *buf = NULL, *buf2 = NULL, *name_chars; |
218 | int nomem = 0; |
219 | struct passwd *p; |
220 | PyObject *bytes, *retval = NULL; |
221 | |
222 | if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL) |
223 | return NULL; |
224 | /* check for embedded null bytes */ |
225 | if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1) |
226 | goto out; |
227 | #ifdef HAVE_GETPWNAM_R |
228 | int status; |
229 | Py_ssize_t bufsize; |
230 | /* Note: 'pwd' will be used via pointer 'p' on getpwnam_r success. */ |
231 | struct passwd pwd; |
232 | |
233 | Py_BEGIN_ALLOW_THREADS |
234 | bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); |
235 | if (bufsize == -1) { |
236 | bufsize = DEFAULT_BUFFER_SIZE; |
237 | } |
238 | |
239 | while(1) { |
240 | buf2 = PyMem_RawRealloc(buf, bufsize); |
241 | if (buf2 == NULL) { |
242 | p = NULL; |
243 | nomem = 1; |
244 | break; |
245 | } |
246 | buf = buf2; |
247 | status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p); |
248 | if (status != 0) { |
249 | p = NULL; |
250 | } |
251 | if (p != NULL || status != ERANGE) { |
252 | break; |
253 | } |
254 | if (bufsize > (PY_SSIZE_T_MAX >> 1)) { |
255 | nomem = 1; |
256 | break; |
257 | } |
258 | bufsize <<= 1; |
259 | } |
260 | |
261 | Py_END_ALLOW_THREADS |
262 | #else |
263 | p = getpwnam(name_chars); |
264 | #endif |
265 | if (p == NULL) { |
266 | if (nomem == 1) { |
267 | PyErr_NoMemory(); |
268 | } |
269 | else { |
270 | PyErr_Format(PyExc_KeyError, |
271 | "getpwnam(): name not found: %R" , name); |
272 | } |
273 | goto out; |
274 | } |
275 | retval = mkpwent(module, p); |
276 | out: |
277 | PyMem_RawFree(buf); |
278 | Py_DECREF(bytes); |
279 | return retval; |
280 | } |
281 | |
282 | #ifdef HAVE_GETPWENT |
283 | /*[clinic input] |
284 | pwd.getpwall |
285 | |
286 | Return a list of all available password database entries, in arbitrary order. |
287 | |
288 | See help(pwd) for more on password database entries. |
289 | [clinic start generated code]*/ |
290 | |
291 | static PyObject * |
292 | pwd_getpwall_impl(PyObject *module) |
293 | /*[clinic end generated code: output=4853d2f5a0afac8a input=d7ecebfd90219b85]*/ |
294 | { |
295 | PyObject *d; |
296 | struct passwd *p; |
297 | if ((d = PyList_New(0)) == NULL) |
298 | return NULL; |
299 | setpwent(); |
300 | while ((p = getpwent()) != NULL) { |
301 | PyObject *v = mkpwent(module, p); |
302 | if (v == NULL || PyList_Append(d, v) != 0) { |
303 | Py_XDECREF(v); |
304 | Py_DECREF(d); |
305 | endpwent(); |
306 | return NULL; |
307 | } |
308 | Py_DECREF(v); |
309 | } |
310 | endpwent(); |
311 | return d; |
312 | } |
313 | #endif |
314 | |
315 | static PyMethodDef pwd_methods[] = { |
316 | PWD_GETPWUID_METHODDEF |
317 | PWD_GETPWNAM_METHODDEF |
318 | #ifdef HAVE_GETPWENT |
319 | PWD_GETPWALL_METHODDEF |
320 | #endif |
321 | {NULL, NULL} /* sentinel */ |
322 | }; |
323 | |
324 | static int |
325 | pwdmodule_exec(PyObject *module) |
326 | { |
327 | pwdmodulestate *state = get_pwd_state(module); |
328 | |
329 | state->StructPwdType = PyStructSequence_NewType(&struct_pwd_type_desc); |
330 | if (state->StructPwdType == NULL) { |
331 | return -1; |
332 | } |
333 | if (PyModule_AddType(module, state->StructPwdType) < 0) { |
334 | return -1; |
335 | } |
336 | return 0; |
337 | } |
338 | |
339 | static PyModuleDef_Slot pwdmodule_slots[] = { |
340 | {Py_mod_exec, pwdmodule_exec}, |
341 | {0, NULL} |
342 | }; |
343 | |
344 | static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) { |
345 | Py_VISIT(get_pwd_state(m)->StructPwdType); |
346 | return 0; |
347 | } |
348 | static int pwdmodule_clear(PyObject *m) { |
349 | Py_CLEAR(get_pwd_state(m)->StructPwdType); |
350 | return 0; |
351 | } |
352 | static void pwdmodule_free(void *m) { |
353 | pwdmodule_clear((PyObject *)m); |
354 | } |
355 | |
356 | static struct PyModuleDef pwdmodule = { |
357 | PyModuleDef_HEAD_INIT, |
358 | .m_name = "pwd" , |
359 | .m_doc = pwd__doc__, |
360 | .m_size = sizeof(pwdmodulestate), |
361 | .m_methods = pwd_methods, |
362 | .m_slots = pwdmodule_slots, |
363 | .m_traverse = pwdmodule_traverse, |
364 | .m_clear = pwdmodule_clear, |
365 | .m_free = pwdmodule_free, |
366 | }; |
367 | |
368 | |
369 | PyMODINIT_FUNC |
370 | PyInit_pwd(void) |
371 | { |
372 | return PyModuleDef_Init(&pwdmodule); |
373 | } |
374 | |