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