Branch data 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 : 60 : get_spwd_state(PyObject *module)
68 : : {
69 : 60 : void *state = PyModule_GetState(module);
70 : : assert(state != NULL);
71 : 60 : 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 : 26 : static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
231 [ + - - + ]: 26 : Py_VISIT(get_spwd_state(m)->StructSpwdType);
232 : 26 : 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 : : }
|