Branch data 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 : 3534 : get_pwd_state(PyObject *module)
56 : : {
57 : 3534 : void *state = PyModule_GetState(module);
58 : : assert(state != NULL);
59 : 3534 : return (pwdmodulestate *)state;
60 : : }
61 : :
62 : : static struct PyModuleDef pwdmodule;
63 : :
64 : : #define DEFAULT_BUFFER_SIZE 1024
65 : :
66 : : static void
67 : 5440 : sets(PyObject *v, int i, const char* val)
68 : : {
69 [ + - ]: 5440 : if (val) {
70 : 5440 : PyObject *o = PyUnicode_DecodeFSDefault(val);
71 : 5440 : 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 : 5440 : }
78 : :
79 : : static PyObject *
80 : 1088 : mkpwent(PyObject *module, struct passwd *p)
81 : : {
82 : 1088 : int setIndex = 0;
83 : 1088 : PyObject *v = PyStructSequence_New(get_pwd_state(module)->StructPwdType);
84 [ - + ]: 1088 : if (v == NULL)
85 : 0 : return NULL;
86 : :
87 : : #define SETS(i,val) sets(v, i, val)
88 : :
89 : 1088 : SETS(setIndex++, p->pw_name);
90 : : #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__)
91 : 1088 : SETS(setIndex++, p->pw_passwd);
92 : : #else
93 : : SETS(setIndex++, "");
94 : : #endif
95 : 1088 : PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid));
96 : 1088 : PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid));
97 : : #if defined(HAVE_STRUCT_PASSWD_PW_GECOS)
98 : 1088 : SETS(setIndex++, p->pw_gecos);
99 : : #else
100 : : SETS(setIndex++, "");
101 : : #endif
102 : 1088 : SETS(setIndex++, p->pw_dir);
103 : 1088 : SETS(setIndex++, p->pw_shell);
104 : :
105 : : #undef SETS
106 : :
107 [ - + ]: 1088 : if (PyErr_Occurred()) {
108 : 0 : Py_XDECREF(v);
109 : 0 : return NULL;
110 : : }
111 : :
112 : 1088 : 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 : 655 : pwd_getpwuid(PyObject *module, PyObject *uidobj)
128 : : /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/
129 : : {
130 : 655 : PyObject *retval = NULL;
131 : : uid_t uid;
132 : 655 : int nomem = 0;
133 : : struct passwd *p;
134 : 655 : char *buf = NULL, *buf2 = NULL;
135 : :
136 [ + + ]: 655 : 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 : 651 : Py_BEGIN_ALLOW_THREADS
149 : 651 : bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
150 [ - + ]: 651 : if (bufsize == -1) {
151 : 0 : bufsize = DEFAULT_BUFFER_SIZE;
152 : : }
153 : :
154 : : while(1) {
155 : 651 : buf2 = PyMem_RawRealloc(buf, bufsize);
156 [ - + ]: 651 : if (buf2 == NULL) {
157 : 0 : p = NULL;
158 : 0 : nomem = 1;
159 : 0 : break;
160 : : }
161 : 651 : buf = buf2;
162 : 651 : status = getpwuid_r(uid, &pwd, buf, bufsize, &p);
163 [ - + ]: 651 : if (status != 0) {
164 : 0 : p = NULL;
165 : : }
166 [ + + - + ]: 651 : 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 : 651 : Py_END_ALLOW_THREADS
177 : : #else
178 : : p = getpwuid(uid);
179 : : #endif
180 [ + + ]: 651 : if (p == NULL) {
181 : 1 : PyMem_RawFree(buf);
182 [ - + ]: 1 : if (nomem == 1) {
183 : : 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 : 650 : retval = mkpwent(module, p);
194 : : #ifdef HAVE_GETPWUID_R
195 : 650 : PyMem_RawFree(buf);
196 : : #endif
197 : 650 : 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 : 87 : pwd_getpwnam_impl(PyObject *module, PyObject *name)
213 : : /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/
214 : : {
215 : 87 : char *buf = NULL, *buf2 = NULL, *name_chars;
216 : 87 : int nomem = 0;
217 : : struct passwd *p;
218 : 87 : PyObject *bytes, *retval = NULL;
219 : :
220 [ - + ]: 87 : if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
221 : 0 : return NULL;
222 : : /* check for embedded null bytes */
223 [ - + ]: 87 : 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 : 87 : Py_BEGIN_ALLOW_THREADS
232 : 87 : bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
233 [ - + ]: 87 : if (bufsize == -1) {
234 : 0 : bufsize = DEFAULT_BUFFER_SIZE;
235 : : }
236 : :
237 : : while(1) {
238 : 87 : buf2 = PyMem_RawRealloc(buf, bufsize);
239 [ - + ]: 87 : if (buf2 == NULL) {
240 : 0 : p = NULL;
241 : 0 : nomem = 1;
242 : 0 : break;
243 : : }
244 : 87 : buf = buf2;
245 : 87 : status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p);
246 [ - + ]: 87 : if (status != 0) {
247 : 0 : p = NULL;
248 : : }
249 [ + + - + ]: 87 : 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 : 87 : Py_END_ALLOW_THREADS
260 : : #else
261 : : p = getpwnam(name_chars);
262 : : #endif
263 [ + + ]: 87 : if (p == NULL) {
264 [ - + ]: 9 : if (nomem == 1) {
265 : : 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 : 78 : retval = mkpwent(module, p);
274 : 87 : out:
275 : 87 : PyMem_RawFree(buf);
276 : 87 : Py_DECREF(bytes);
277 : 87 : 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 [ + + ]: 366 : while ((p = getpwent()) != NULL) {
299 : 360 : PyObject *v = mkpwent(module, p);
300 [ + - - + ]: 360 : 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 : 360 : 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 : 93 : pwdmodule_exec(PyObject *module)
324 : : {
325 : 93 : pwdmodulestate *state = get_pwd_state(module);
326 : :
327 : 93 : state->StructPwdType = PyStructSequence_NewType(&struct_pwd_type_desc);
328 [ - + ]: 93 : if (state->StructPwdType == NULL) {
329 : 0 : return -1;
330 : : }
331 [ - + ]: 93 : if (PyModule_AddType(module, state->StructPwdType) < 0) {
332 : 0 : return -1;
333 : : }
334 : 93 : return 0;
335 : : }
336 : :
337 : : static PyModuleDef_Slot pwdmodule_slots[] = {
338 : : {Py_mod_exec, pwdmodule_exec},
339 : : {0, NULL}
340 : : };
341 : :
342 : 1040 : static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
343 [ + - - + ]: 1040 : Py_VISIT(get_pwd_state(m)->StructPwdType);
344 : 1040 : return 0;
345 : : }
346 : 180 : static int pwdmodule_clear(PyObject *m) {
347 [ + + ]: 180 : Py_CLEAR(get_pwd_state(m)->StructPwdType);
348 : 180 : return 0;
349 : : }
350 : 93 : static void pwdmodule_free(void *m) {
351 : 93 : pwdmodule_clear((PyObject *)m);
352 : 93 : }
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 : 93 : PyInit_pwd(void)
369 : : {
370 : 93 : return PyModuleDef_Init(&pwdmodule);
371 : : }
|