1
2/* UNIX shadow password file access module */
3/* A lot of code has been taken from pwdmodule.c */
4/* For info also see http://www.unixpapa.com/incnote/passwd.html */
5
6#include "Python.h"
7
8#include <sys/types.h>
9#ifdef HAVE_SHADOW_H
10#include <shadow.h>
11#endif
12
13#include "clinic/spwdmodule.c.h"
14
15/*[clinic input]
16module spwd
17[clinic start generated code]*/
18/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c0b841b90a6a07ce]*/
19
20PyDoc_STRVAR(spwd__doc__,
21"This module provides access to the Unix shadow password database.\n\
22It is available on various Unix versions.\n\
23\n\
24Shadow password database entries are reported as 9-tuples of type struct_spwd,\n\
25containing the following items from the password database (see `<shadow.h>'):\n\
26sp_namp, sp_pwdp, sp_lstchg, sp_min, sp_max, sp_warn, sp_inact, sp_expire, sp_flag.\n\
27The sp_namp and sp_pwdp are strings, the rest are integers.\n\
28An exception is raised if the entry asked for cannot be found.\n\
29You have to be root to be able to use this module.");
30
31
32#if defined(HAVE_GETSPNAM) || defined(HAVE_GETSPENT)
33
34static PyStructSequence_Field struct_spwd_type_fields[] = {
35 {"sp_namp", "login name"},
36 {"sp_pwdp", "encrypted password"},
37 {"sp_lstchg", "date of last change"},
38 {"sp_min", "min #days between changes"},
39 {"sp_max", "max #days between changes"},
40 {"sp_warn", "#days before pw expires to warn user about it"},
41 {"sp_inact", "#days after pw expires until account is disabled"},
42 {"sp_expire", "#days since 1970-01-01 when account expires"},
43 {"sp_flag", "reserved"},
44 {"sp_nam", "login name; deprecated"}, /* Backward compatibility */
45 {"sp_pwd", "encrypted password; deprecated"}, /* Backward compatibility */
46 {0}
47};
48
49PyDoc_STRVAR(struct_spwd__doc__,
50"spwd.struct_spwd: Results from getsp*() routines.\n\n\
51This object may be accessed either as a 9-tuple of\n\
52 (sp_namp,sp_pwdp,sp_lstchg,sp_min,sp_max,sp_warn,sp_inact,sp_expire,sp_flag)\n\
53or via the object attributes as named in the above tuple.");
54
55static PyStructSequence_Desc struct_spwd_type_desc = {
56 "spwd.struct_spwd",
57 struct_spwd__doc__,
58 struct_spwd_type_fields,
59 9,
60};
61
62typedef struct {
63 PyTypeObject *StructSpwdType;
64} spwdmodulestate;
65
66static inline spwdmodulestate*
67get_spwd_state(PyObject *module)
68{
69 void *state = PyModule_GetState(module);
70 assert(state != NULL);
71 return (spwdmodulestate *)state;
72}
73
74static struct PyModuleDef spwdmodule;
75
76static void
77sets(PyObject *v, int i, const char* val)
78{
79 if (val) {
80 PyObject *o = PyUnicode_DecodeFSDefault(val);
81 PyStructSequence_SET_ITEM(v, i, o);
82 } else {
83 PyStructSequence_SET_ITEM(v, i, Py_None);
84 Py_INCREF(Py_None);
85 }
86}
87
88static PyObject *mkspent(PyObject *module, struct spwd *p)
89{
90 int setIndex = 0;
91 PyObject *v = PyStructSequence_New(get_spwd_state(module)->StructSpwdType);
92 if (v == NULL)
93 return NULL;
94
95#define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val))
96#define SETS(i,val) sets(v, i, val)
97
98 SETS(setIndex++, p->sp_namp);
99 SETS(setIndex++, p->sp_pwdp);
100 SETI(setIndex++, p->sp_lstchg);
101 SETI(setIndex++, p->sp_min);
102 SETI(setIndex++, p->sp_max);
103 SETI(setIndex++, p->sp_warn);
104 SETI(setIndex++, p->sp_inact);
105 SETI(setIndex++, p->sp_expire);
106 SETI(setIndex++, p->sp_flag);
107 SETS(setIndex++, p->sp_namp); /* Backward compatibility for sp_nam */
108 SETS(setIndex++, p->sp_pwdp); /* Backward compatibility for sp_pwd */
109
110#undef SETS
111#undef SETI
112
113 if (PyErr_Occurred()) {
114 Py_DECREF(v);
115 return NULL;
116 }
117
118 return v;
119}
120
121#endif /* HAVE_GETSPNAM || HAVE_GETSPENT */
122
123
124#ifdef HAVE_GETSPNAM
125
126/*[clinic input]
127spwd.getspnam
128
129 arg: unicode
130 /
131
132Return the shadow password database entry for the given user name.
133
134See `help(spwd)` for more on shadow password database entries.
135[clinic start generated code]*/
136
137static PyObject *
138spwd_getspnam_impl(PyObject *module, PyObject *arg)
139/*[clinic end generated code: output=701250cf57dc6ebe input=dd89429e6167a00f]*/
140{
141 char *name;
142 struct spwd *p;
143 PyObject *bytes, *retval = NULL;
144
145 if ((bytes = PyUnicode_EncodeFSDefault(arg)) == NULL)
146 return NULL;
147 /* check for embedded null bytes */
148 if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1)
149 goto out;
150 if ((p = getspnam(name)) == NULL) {
151 if (errno != 0)
152 PyErr_SetFromErrno(PyExc_OSError);
153 else
154 PyErr_SetString(PyExc_KeyError, "getspnam(): name not found");
155 goto out;
156 }
157 retval = mkspent(module, p);
158out:
159 Py_DECREF(bytes);
160 return retval;
161}
162
163#endif /* HAVE_GETSPNAM */
164
165#ifdef HAVE_GETSPENT
166
167/*[clinic input]
168spwd.getspall
169
170Return a list of all available shadow password database entries, in arbitrary order.
171
172See `help(spwd)` for more on shadow password database entries.
173[clinic start generated code]*/
174
175static PyObject *
176spwd_getspall_impl(PyObject *module)
177/*[clinic end generated code: output=4fda298d6bf6d057 input=b2c84b7857d622bd]*/
178{
179 PyObject *d;
180 struct spwd *p;
181 if ((d = PyList_New(0)) == NULL)
182 return NULL;
183 setspent();
184 while ((p = getspent()) != NULL) {
185 PyObject *v = mkspent(module, p);
186 if (v == NULL || PyList_Append(d, v) != 0) {
187 Py_XDECREF(v);
188 Py_DECREF(d);
189 endspent();
190 return NULL;
191 }
192 Py_DECREF(v);
193 }
194 endspent();
195 return d;
196}
197
198#endif /* HAVE_GETSPENT */
199
200static PyMethodDef spwd_methods[] = {
201#ifdef HAVE_GETSPNAM
202 SPWD_GETSPNAM_METHODDEF
203#endif
204#ifdef HAVE_GETSPENT
205 SPWD_GETSPALL_METHODDEF
206#endif
207 {NULL, NULL} /* sentinel */
208};
209
210static int
211spwdmodule_exec(PyObject *module)
212{
213 spwdmodulestate *state = get_spwd_state(module);
214
215 state->StructSpwdType = PyStructSequence_NewType(&struct_spwd_type_desc);
216 if (state->StructSpwdType == NULL) {
217 return -1;
218 }
219 if (PyModule_AddType(module, state->StructSpwdType) < 0) {
220 return -1;
221 }
222 return 0;
223}
224
225static PyModuleDef_Slot spwdmodule_slots[] = {
226 {Py_mod_exec, spwdmodule_exec},
227 {0, NULL}
228};
229
230static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
231 Py_VISIT(get_spwd_state(m)->StructSpwdType);
232 return 0;
233}
234
235static int spwdmodule_clear(PyObject *m) {
236 Py_CLEAR(get_spwd_state(m)->StructSpwdType);
237 return 0;
238}
239
240static void spwdmodule_free(void *m) {
241 spwdmodule_clear((PyObject *)m);
242}
243
244static struct PyModuleDef spwdmodule = {
245 PyModuleDef_HEAD_INIT,
246 .m_name = "spwd",
247 .m_doc = spwd__doc__,
248 .m_size = sizeof(spwdmodulestate),
249 .m_methods = spwd_methods,
250 .m_slots = spwdmodule_slots,
251 .m_traverse = spwdmodule_traverse,
252 .m_clear = spwdmodule_clear,
253 .m_free = spwdmodule_free,
254};
255
256PyMODINIT_FUNC
257PyInit_spwd(void)
258{
259 return PyModuleDef_Init(&spwdmodule);
260}
261