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 #define DEFAULT_BUFFER_SIZE 1024
54
55 static void
sets(PyObject * v,int i,const char * val)56 sets(PyObject *v, int i, const char* val)
57 {
58 if (val) {
59 PyObject *o = PyUnicode_DecodeFSDefault(val);
60 PyStructSequence_SET_ITEM(v, i, o);
61 }
62 else {
63 PyStructSequence_SET_ITEM(v, i, Py_None);
64 Py_INCREF(Py_None);
65 }
66 }
67
68 static PyObject *
mkpwent(struct passwd * p)69 mkpwent(struct passwd *p)
70 {
71 int setIndex = 0;
72 PyObject *v = PyStructSequence_New(&StructPwdType);
73 if (v == NULL)
74 return NULL;
75
76 #define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val))
77 #define SETS(i,val) sets(v, i, val)
78
79 SETS(setIndex++, p->pw_name);
80 #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__)
81 SETS(setIndex++, p->pw_passwd);
82 #else
83 SETS(setIndex++, "");
84 #endif
85 PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid));
86 PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid));
87 #if defined(HAVE_STRUCT_PASSWD_PW_GECOS)
88 SETS(setIndex++, p->pw_gecos);
89 #else
90 SETS(setIndex++, "");
91 #endif
92 SETS(setIndex++, p->pw_dir);
93 SETS(setIndex++, p->pw_shell);
94
95 #undef SETS
96 #undef SETI
97
98 if (PyErr_Occurred()) {
99 Py_XDECREF(v);
100 return NULL;
101 }
102
103 return v;
104 }
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 *
pwd_getpwuid(PyObject * module,PyObject * uidobj)118 pwd_getpwuid(PyObject *module, PyObject *uidobj)
119 /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/
120 {
121 PyObject *retval = NULL;
122 uid_t uid;
123 int nomem = 0;
124 struct passwd *p;
125 char *buf = NULL, *buf2 = NULL;
126
127 if (!_Py_Uid_Converter(uidobj, &uid)) {
128 if (PyErr_ExceptionMatches(PyExc_OverflowError))
129 PyErr_Format(PyExc_KeyError,
130 "getpwuid(): uid not found");
131 return NULL;
132 }
133 #ifdef HAVE_GETPWUID_R
134 int status;
135 Py_ssize_t bufsize;
136 /* Note: 'pwd' will be used via pointer 'p' on getpwuid_r success. */
137 struct passwd pwd;
138
139 Py_BEGIN_ALLOW_THREADS
140 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
141 if (bufsize == -1) {
142 bufsize = DEFAULT_BUFFER_SIZE;
143 }
144
145 while(1) {
146 buf2 = PyMem_RawRealloc(buf, bufsize);
147 if (buf2 == NULL) {
148 p = NULL;
149 nomem = 1;
150 break;
151 }
152 buf = buf2;
153 status = getpwuid_r(uid, &pwd, buf, bufsize, &p);
154 if (status != 0) {
155 p = NULL;
156 }
157 if (p != NULL || status != ERANGE) {
158 break;
159 }
160 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
161 nomem = 1;
162 break;
163 }
164 bufsize <<= 1;
165 }
166
167 Py_END_ALLOW_THREADS
168 #else
169 p = getpwuid(uid);
170 #endif
171 if (p == NULL) {
172 PyMem_RawFree(buf);
173 if (nomem == 1) {
174 return PyErr_NoMemory();
175 }
176 PyObject *uid_obj = _PyLong_FromUid(uid);
177 if (uid_obj == NULL)
178 return NULL;
179 PyErr_Format(PyExc_KeyError,
180 "getpwuid(): uid not found: %S", uid_obj);
181 Py_DECREF(uid_obj);
182 return NULL;
183 }
184 retval = mkpwent(p);
185 #ifdef HAVE_GETPWUID_R
186 PyMem_RawFree(buf);
187 #endif
188 return retval;
189 }
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 *
pwd_getpwnam_impl(PyObject * module,PyObject * name)203 pwd_getpwnam_impl(PyObject *module, PyObject *name)
204 /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/
205 {
206 char *buf = NULL, *buf2 = NULL, *name_chars;
207 int nomem = 0;
208 struct passwd *p;
209 PyObject *bytes, *retval = NULL;
210
211 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
212 return NULL;
213 /* check for embedded null bytes */
214 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
215 goto out;
216 #ifdef HAVE_GETPWNAM_R
217 int status;
218 Py_ssize_t bufsize;
219 /* Note: 'pwd' will be used via pointer 'p' on getpwnam_r success. */
220 struct passwd pwd;
221
222 Py_BEGIN_ALLOW_THREADS
223 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
224 if (bufsize == -1) {
225 bufsize = DEFAULT_BUFFER_SIZE;
226 }
227
228 while(1) {
229 buf2 = PyMem_RawRealloc(buf, bufsize);
230 if (buf2 == NULL) {
231 p = NULL;
232 nomem = 1;
233 break;
234 }
235 buf = buf2;
236 status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p);
237 if (status != 0) {
238 p = NULL;
239 }
240 if (p != NULL || status != ERANGE) {
241 break;
242 }
243 if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
244 nomem = 1;
245 break;
246 }
247 bufsize <<= 1;
248 }
249
250 Py_END_ALLOW_THREADS
251 #else
252 p = getpwnam(name_chars);
253 #endif
254 if (p == NULL) {
255 if (nomem == 1) {
256 PyErr_NoMemory();
257 }
258 else {
259 PyErr_Format(PyExc_KeyError,
260 "getpwnam(): name not found: %R", name);
261 }
262 goto out;
263 }
264 retval = mkpwent(p);
265 out:
266 PyMem_RawFree(buf);
267 Py_DECREF(bytes);
268 return retval;
269 }
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 *
pwd_getpwall_impl(PyObject * module)281 pwd_getpwall_impl(PyObject *module)
282 /*[clinic end generated code: output=4853d2f5a0afac8a input=d7ecebfd90219b85]*/
283 {
284 PyObject *d;
285 struct passwd *p;
286 if ((d = PyList_New(0)) == NULL)
287 return NULL;
288 setpwent();
289 while ((p = getpwent()) != NULL) {
290 PyObject *v = mkpwent(p);
291 if (v == NULL || PyList_Append(d, v) != 0) {
292 Py_XDECREF(v);
293 Py_DECREF(d);
294 endpwent();
295 return NULL;
296 }
297 Py_DECREF(v);
298 }
299 endpwent();
300 return d;
301 }
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
PyInit_pwd(void)327 PyInit_pwd(void)
328 {
329 PyObject *m;
330 m = PyModule_Create(&pwdmodule);
331 if (m == NULL)
332 return NULL;
333
334 if (!initialized) {
335 if (PyStructSequence_InitType2(&StructPwdType,
336 &struct_pwd_type_desc) < 0)
337 return NULL;
338 initialized = 1;
339 }
340 Py_INCREF((PyObject *) &StructPwdType);
341 PyModule_AddObject(m, "struct_passwd", (PyObject *) &StructPwdType);
342 return m;
343 }
344