Coverage Report

Created: 2025-07-11 06:59

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