Line data Source code
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]
16 : module spwd
17 : [clinic start generated code]*/
18 : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c0b841b90a6a07ce]*/
19 :
20 : PyDoc_STRVAR(spwd__doc__,
21 : "This module provides access to the Unix shadow password database.\n\
22 : It is available on various Unix versions.\n\
23 : \n\
24 : Shadow password database entries are reported as 9-tuples of type struct_spwd,\n\
25 : containing the following items from the password database (see `<shadow.h>'):\n\
26 : sp_namp, sp_pwdp, sp_lstchg, sp_min, sp_max, sp_warn, sp_inact, sp_expire, sp_flag.\n\
27 : The sp_namp and sp_pwdp are strings, the rest are integers.\n\
28 : An exception is raised if the entry asked for cannot be found.\n\
29 : You have to be root to be able to use this module.");
30 :
31 :
32 : #if defined(HAVE_GETSPNAM) || defined(HAVE_GETSPENT)
33 :
34 : static 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 :
49 : PyDoc_STRVAR(struct_spwd__doc__,
50 : "spwd.struct_spwd: Results from getsp*() routines.\n\n\
51 : This 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\
53 : or via the object attributes as named in the above tuple.");
54 :
55 : static PyStructSequence_Desc struct_spwd_type_desc = {
56 : "spwd.struct_spwd",
57 : struct_spwd__doc__,
58 : struct_spwd_type_fields,
59 : 9,
60 : };
61 :
62 : typedef struct {
63 : PyTypeObject *StructSpwdType;
64 : } spwdmodulestate;
65 :
66 : static inline spwdmodulestate*
67 64 : get_spwd_state(PyObject *module)
68 : {
69 64 : void *state = PyModule_GetState(module);
70 64 : assert(state != NULL);
71 64 : return (spwdmodulestate *)state;
72 : }
73 :
74 : static struct PyModuleDef spwdmodule;
75 :
76 : static void
77 0 : sets(PyObject *v, int i, const char* val)
78 : {
79 0 : if (val) {
80 0 : PyObject *o = PyUnicode_DecodeFSDefault(val);
81 0 : PyStructSequence_SET_ITEM(v, i, o);
82 : } else {
83 0 : PyStructSequence_SET_ITEM(v, i, Py_None);
84 0 : Py_INCREF(Py_None);
85 : }
86 0 : }
87 :
88 0 : static PyObject *mkspent(PyObject *module, struct spwd *p)
89 : {
90 0 : int setIndex = 0;
91 0 : PyObject *v = PyStructSequence_New(get_spwd_state(module)->StructSpwdType);
92 0 : if (v == NULL)
93 0 : 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 0 : SETS(setIndex++, p->sp_namp);
99 0 : SETS(setIndex++, p->sp_pwdp);
100 0 : SETI(setIndex++, p->sp_lstchg);
101 0 : SETI(setIndex++, p->sp_min);
102 0 : SETI(setIndex++, p->sp_max);
103 0 : SETI(setIndex++, p->sp_warn);
104 0 : SETI(setIndex++, p->sp_inact);
105 0 : SETI(setIndex++, p->sp_expire);
106 0 : SETI(setIndex++, p->sp_flag);
107 0 : SETS(setIndex++, p->sp_namp); /* Backward compatibility for sp_nam */
108 0 : SETS(setIndex++, p->sp_pwdp); /* Backward compatibility for sp_pwd */
109 :
110 : #undef SETS
111 : #undef SETI
112 :
113 0 : if (PyErr_Occurred()) {
114 0 : Py_DECREF(v);
115 0 : return NULL;
116 : }
117 :
118 0 : return v;
119 : }
120 :
121 : #endif /* HAVE_GETSPNAM || HAVE_GETSPENT */
122 :
123 :
124 : #ifdef HAVE_GETSPNAM
125 :
126 : /*[clinic input]
127 : spwd.getspnam
128 :
129 : arg: unicode
130 : /
131 :
132 : Return the shadow password database entry for the given user name.
133 :
134 : See `help(spwd)` for more on shadow password database entries.
135 : [clinic start generated code]*/
136 :
137 : static PyObject *
138 1 : spwd_getspnam_impl(PyObject *module, PyObject *arg)
139 : /*[clinic end generated code: output=701250cf57dc6ebe input=dd89429e6167a00f]*/
140 : {
141 : char *name;
142 : struct spwd *p;
143 1 : PyObject *bytes, *retval = NULL;
144 :
145 1 : if ((bytes = PyUnicode_EncodeFSDefault(arg)) == NULL)
146 0 : return NULL;
147 : /* check for embedded null bytes */
148 1 : if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1)
149 0 : goto out;
150 1 : if ((p = getspnam(name)) == NULL) {
151 1 : if (errno != 0)
152 1 : PyErr_SetFromErrno(PyExc_OSError);
153 : else
154 0 : PyErr_SetString(PyExc_KeyError, "getspnam(): name not found");
155 1 : goto out;
156 : }
157 0 : retval = mkspent(module, p);
158 1 : out:
159 1 : Py_DECREF(bytes);
160 1 : return retval;
161 : }
162 :
163 : #endif /* HAVE_GETSPNAM */
164 :
165 : #ifdef HAVE_GETSPENT
166 :
167 : /*[clinic input]
168 : spwd.getspall
169 :
170 : Return a list of all available shadow password database entries, in arbitrary order.
171 :
172 : See `help(spwd)` for more on shadow password database entries.
173 : [clinic start generated code]*/
174 :
175 : static PyObject *
176 0 : spwd_getspall_impl(PyObject *module)
177 : /*[clinic end generated code: output=4fda298d6bf6d057 input=b2c84b7857d622bd]*/
178 : {
179 : PyObject *d;
180 : struct spwd *p;
181 0 : if ((d = PyList_New(0)) == NULL)
182 0 : return NULL;
183 0 : setspent();
184 0 : while ((p = getspent()) != NULL) {
185 0 : PyObject *v = mkspent(module, p);
186 0 : if (v == NULL || PyList_Append(d, v) != 0) {
187 0 : Py_XDECREF(v);
188 0 : Py_DECREF(d);
189 0 : endspent();
190 0 : return NULL;
191 : }
192 0 : Py_DECREF(v);
193 : }
194 0 : endspent();
195 0 : return d;
196 : }
197 :
198 : #endif /* HAVE_GETSPENT */
199 :
200 : static 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 :
210 : static int
211 2 : spwdmodule_exec(PyObject *module)
212 : {
213 2 : spwdmodulestate *state = get_spwd_state(module);
214 :
215 2 : state->StructSpwdType = PyStructSequence_NewType(&struct_spwd_type_desc);
216 2 : if (state->StructSpwdType == NULL) {
217 0 : return -1;
218 : }
219 2 : if (PyModule_AddType(module, state->StructSpwdType) < 0) {
220 0 : return -1;
221 : }
222 2 : return 0;
223 : }
224 :
225 : static PyModuleDef_Slot spwdmodule_slots[] = {
226 : {Py_mod_exec, spwdmodule_exec},
227 : {0, NULL}
228 : };
229 :
230 28 : static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
231 28 : Py_VISIT(get_spwd_state(m)->StructSpwdType);
232 28 : return 0;
233 : }
234 :
235 4 : static int spwdmodule_clear(PyObject *m) {
236 4 : Py_CLEAR(get_spwd_state(m)->StructSpwdType);
237 4 : return 0;
238 : }
239 :
240 2 : static void spwdmodule_free(void *m) {
241 2 : spwdmodule_clear((PyObject *)m);
242 2 : }
243 :
244 : static 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 :
256 : PyMODINIT_FUNC
257 2 : PyInit_spwd(void)
258 : {
259 2 : if (PyErr_WarnEx(PyExc_DeprecationWarning,
260 : "'spwd' is deprecated and slated for removal in "
261 : "Python 3.13",
262 : 7)) {
263 0 : return NULL;
264 : }
265 :
266 2 : return PyModuleDef_Init(&spwdmodule);
267 : }
|