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 | get_spwd_state(PyObject *module) |
68 | { |
69 | void *state = PyModule_GetState(module); |
70 | assert(state != NULL); |
71 | return (spwdmodulestate *)state; |
72 | } |
73 | |
74 | static struct PyModuleDef spwdmodule; |
75 | |
76 | static void |
77 | sets(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 | |
88 | static 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] |
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 | 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 | 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); |
158 | out: |
159 | Py_DECREF(bytes); |
160 | 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 | spwd_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 | |
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 | spwdmodule_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 | |
225 | static PyModuleDef_Slot spwdmodule_slots[] = { |
226 | {Py_mod_exec, spwdmodule_exec}, |
227 | {0, NULL} |
228 | }; |
229 | |
230 | static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) { |
231 | Py_VISIT(get_spwd_state(m)->StructSpwdType); |
232 | return 0; |
233 | } |
234 | |
235 | static int spwdmodule_clear(PyObject *m) { |
236 | Py_CLEAR(get_spwd_state(m)->StructSpwdType); |
237 | return 0; |
238 | } |
239 | |
240 | static void spwdmodule_free(void *m) { |
241 | spwdmodule_clear((PyObject *)m); |
242 | } |
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 | PyInit_spwd(void) |
258 | { |
259 | return PyModuleDef_Init(&spwdmodule); |
260 | } |
261 | |