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*
get_pwd_state(PyObject * module)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
sets(PyObject * v,int i,const char * val)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 *
mkpwent(PyObject * module,struct passwd * p)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 SETS(i,val) sets(v, i, val)
88
89 SETS(setIndex++, p->pw_name);
90 #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__)
91 SETS(setIndex++, p->pw_passwd);
92 #else
93 SETS(setIndex++, "");
94 #endif
95 PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid));
96 PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid));
97 #if defined(HAVE_STRUCT_PASSWD_PW_GECOS)
98 SETS(setIndex++, p->pw_gecos);
99 #else
100 SETS(setIndex++, "");
101 #endif
102 SETS(setIndex++, p->pw_dir);
103 SETS(setIndex++, p->pw_shell);
104
105 #undef SETS
106
107 if (PyErr_Occurred()) {
108 Py_XDECREF(v);
109 return NULL;
110 }
111
112 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 *
pwd_getpwuid(PyObject * module,PyObject * uidobj)127 pwd_getpwuid(PyObject *module, PyObject *uidobj)
128 /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/
129 {
130 PyObject *retval = NULL;
131 uid_t uid;
132 int nomem = 0;
133 struct passwd *p;
134 char *buf = NULL, *buf2 = NULL;
135
136 if (!_Py_Uid_Converter(uidobj, &uid)) {
137 if (PyErr_ExceptionMatches(PyExc_OverflowError))
138 PyErr_Format(PyExc_KeyError,
139 "getpwuid(): uid not found");
140 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 Py_BEGIN_ALLOW_THREADS
149 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
150 if (bufsize == -1) {
151 bufsize = DEFAULT_BUFFER_SIZE;
152 }
153
154 while(1) {
155 buf2 = PyMem_RawRealloc(buf, bufsize);
156 if (buf2 == NULL) {
157 p = NULL;
158 nomem = 1;
159 break;
160 }
161 buf = buf2;
162 status = getpwuid_r(uid, &pwd, buf, bufsize, &p);
163 if (status != 0) {
164 p = NULL;
165 }
166 if (p != NULL || status != ERANGE) {
167 break;
168 }
169 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
170 nomem = 1;
171 break;
172 }
173 bufsize <<= 1;
174 }
175
176 Py_END_ALLOW_THREADS
177 #else
178 p = getpwuid(uid);
179 #endif
180 if (p == NULL) {
181 PyMem_RawFree(buf);
182 if (nomem == 1) {
183 return PyErr_NoMemory();
184 }
185 PyObject *uid_obj = _PyLong_FromUid(uid);
186 if (uid_obj == NULL)
187 return NULL;
188 PyErr_Format(PyExc_KeyError,
189 "getpwuid(): uid not found: %S", uid_obj);
190 Py_DECREF(uid_obj);
191 return NULL;
192 }
193 retval = mkpwent(module, p);
194 #ifdef HAVE_GETPWUID_R
195 PyMem_RawFree(buf);
196 #endif
197 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 *
pwd_getpwnam_impl(PyObject * module,PyObject * name)212 pwd_getpwnam_impl(PyObject *module, PyObject *name)
213 /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/
214 {
215 char *buf = NULL, *buf2 = NULL, *name_chars;
216 int nomem = 0;
217 struct passwd *p;
218 PyObject *bytes, *retval = NULL;
219
220 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
221 return NULL;
222 /* check for embedded null bytes */
223 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
224 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 Py_BEGIN_ALLOW_THREADS
232 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
233 if (bufsize == -1) {
234 bufsize = DEFAULT_BUFFER_SIZE;
235 }
236
237 while(1) {
238 buf2 = PyMem_RawRealloc(buf, bufsize);
239 if (buf2 == NULL) {
240 p = NULL;
241 nomem = 1;
242 break;
243 }
244 buf = buf2;
245 status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p);
246 if (status != 0) {
247 p = NULL;
248 }
249 if (p != NULL || status != ERANGE) {
250 break;
251 }
252 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
253 nomem = 1;
254 break;
255 }
256 bufsize <<= 1;
257 }
258
259 Py_END_ALLOW_THREADS
260 #else
261 p = getpwnam(name_chars);
262 #endif
263 if (p == NULL) {
264 if (nomem == 1) {
265 PyErr_NoMemory();
266 }
267 else {
268 PyErr_Format(PyExc_KeyError,
269 "getpwnam(): name not found: %R", name);
270 }
271 goto out;
272 }
273 retval = mkpwent(module, p);
274 out:
275 PyMem_RawFree(buf);
276 Py_DECREF(bytes);
277 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 *
pwd_getpwall_impl(PyObject * module)290 pwd_getpwall_impl(PyObject *module)
291 /*[clinic end generated code: output=4853d2f5a0afac8a input=d7ecebfd90219b85]*/
292 {
293 PyObject *d;
294 struct passwd *p;
295 if ((d = PyList_New(0)) == NULL)
296 return NULL;
297 setpwent();
298 while ((p = getpwent()) != NULL) {
299 PyObject *v = mkpwent(module, p);
300 if (v == NULL || PyList_Append(d, v) != 0) {
301 Py_XDECREF(v);
302 Py_DECREF(d);
303 endpwent();
304 return NULL;
305 }
306 Py_DECREF(v);
307 }
308 endpwent();
309 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
pwdmodule_exec(PyObject * module)323 pwdmodule_exec(PyObject *module)
324 {
325 pwdmodulestate *state = get_pwd_state(module);
326
327 state->StructPwdType = PyStructSequence_NewType(&struct_pwd_type_desc);
328 if (state->StructPwdType == NULL) {
329 return -1;
330 }
331 if (PyModule_AddType(module, state->StructPwdType) < 0) {
332 return -1;
333 }
334 return 0;
335 }
336
337 static PyModuleDef_Slot pwdmodule_slots[] = {
338 {Py_mod_exec, pwdmodule_exec},
339 {0, NULL}
340 };
341
pwdmodule_traverse(PyObject * m,visitproc visit,void * arg)342 static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
343 Py_VISIT(get_pwd_state(m)->StructPwdType);
344 return 0;
345 }
pwdmodule_clear(PyObject * m)346 static int pwdmodule_clear(PyObject *m) {
347 Py_CLEAR(get_pwd_state(m)->StructPwdType);
348 return 0;
349 }
pwdmodule_free(void * m)350 static void pwdmodule_free(void *m) {
351 pwdmodule_clear((PyObject *)m);
352 }
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
PyInit_pwd(void)368 PyInit_pwd(void)
369 {
370 return PyModuleDef_Init(&pwdmodule);
371 }
372