• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*
get_spwd_state(PyObject * module)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
sets(PyObject * v,int i,const char * val)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 
mkspent(PyObject * module,struct spwd * p)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 *
spwd_getspnam_impl(PyObject * module,PyObject * arg)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 *
spwd_getspall_impl(PyObject * module)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
spwdmodule_exec(PyObject * module)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 
spwdmodule_traverse(PyObject * m,visitproc visit,void * arg)230 static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
231     Py_VISIT(get_spwd_state(m)->StructSpwdType);
232     return 0;
233 }
234 
spwdmodule_clear(PyObject * m)235 static int spwdmodule_clear(PyObject *m) {
236     Py_CLEAR(get_spwd_state(m)->StructSpwdType);
237     return 0;
238 }
239 
spwdmodule_free(void * m)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
PyInit_spwd(void)257 PyInit_spwd(void)
258 {
259     return PyModuleDef_Init(&spwdmodule);
260 }
261