Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/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
typedef struct {
51
    PyTypeObject *StructPwdType;
52
} pwdmodulestate;
53
54
static inline pwdmodulestate*
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
67
sets(PyObject *v, int i, const char* val)
68
{
69
  if (val) {
  Branch (69:7): [True: 3.92k, False: 0]
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 *
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)
  Branch (84:9): [True: 0, False: 785]
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()) {
  Branch (107:9): [True: 0, False: 785]
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 *
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)) {
  Branch (136:9): [True: 4, False: 586]
137
        if (PyErr_ExceptionMatches(PyExc_OverflowError))
  Branch (137:13): [True: 3, False: 1]
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) {
  Branch (150:9): [True: 0, False: 586]
151
        bufsize = DEFAULT_BUFFER_SIZE;
152
    }
153
154
    while(1) {
  Branch (154:11): [Folded - Ignored]
155
        buf2 = PyMem_RawRealloc(buf, bufsize);
156
        if (buf2 == NULL) {
  Branch (156:13): [True: 0, False: 586]
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) {
  Branch (163:13): [True: 0, False: 586]
164
            p = NULL;
165
        }
166
        if (p != NULL || 
status != ERANGE1
) {
  Branch (166:13): [True: 585, False: 1]
  Branch (166:26): [True: 1, False: 0]
167
            break;
168
        }
169
        if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
  Branch (169:13): [True: 0, False: 0]
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) {
  Branch (180:9): [True: 1, False: 585]
181
        PyMem_RawFree(buf);
182
        if (nomem == 1) {
  Branch (182:13): [True: 0, False: 1]
183
            return PyErr_NoMemory();
184
        }
185
        PyObject *uid_obj = _PyLong_FromUid(uid);
186
        if (uid_obj == NULL)
  Branch (186:13): [True: 0, False: 1]
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 *
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)
  Branch (220:9): [True: 0, False: 53]
221
        return NULL;
222
    /* check for embedded null bytes */
223
    if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
  Branch (223:9): [True: 0, False: 53]
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) {
  Branch (233:9): [True: 0, False: 53]
234
        bufsize = DEFAULT_BUFFER_SIZE;
235
    }
236
237
    while(1) {
  Branch (237:11): [Folded - Ignored]
238
        buf2 = PyMem_RawRealloc(buf, bufsize);
239
        if (buf2 == NULL) {
  Branch (239:13): [True: 0, False: 53]
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) {
  Branch (246:13): [True: 0, False: 53]
247
            p = NULL;
248
        }
249
        if (p != NULL || 
status != ERANGE9
) {
  Branch (249:13): [True: 44, False: 9]
  Branch (249:26): [True: 9, False: 0]
250
            break;
251
        }
252
        if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
  Branch (252:13): [True: 0, False: 0]
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) {
  Branch (263:9): [True: 9, False: 44]
264
        if (nomem == 1) {
  Branch (264:13): [True: 0, False: 9]
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 *
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)
  Branch (295:9): [True: 0, False: 6]
296
        return NULL;
297
    setpwent();
298
    while ((p = getpwent()) != NULL) {
  Branch (298:12): [True: 156, False: 6]
299
        PyObject *v = mkpwent(module, p);
300
        if (v == NULL || PyList_Append(d, v) != 0) {
  Branch (300:13): [True: 0, False: 156]
  Branch (300:26): [True: 0, False: 156]
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
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) {
  Branch (328:9): [True: 0, False: 1]
329
        return -1;
330
    }
331
    if (PyModule_AddType(module, state->StructPwdType) < 0) {
  Branch (331:9): [True: 0, False: 1]
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
342
static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
343
    Py_VISIT(get_pwd_state(m)->StructPwdType);
344
    return 0;
345
}
346
static int pwdmodule_clear(PyObject *m) {
347
    Py_CLEAR(get_pwd_state(m)->StructPwdType);
348
    return 0;
349
}
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
368
PyInit_pwd(void)
369
{
370
    return PyModuleDef_Init(&pwdmodule);
371
}