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 static int initialized;
63 static PyTypeObject StructSpwdType;
64 
65 
66 static void
sets(PyObject * v,int i,const char * val)67 sets(PyObject *v, int i, const char* val)
68 {
69   if (val) {
70       PyObject *o = PyUnicode_DecodeFSDefault(val);
71       PyStructSequence_SET_ITEM(v, i, o);
72   } else {
73       PyStructSequence_SET_ITEM(v, i, Py_None);
74       Py_INCREF(Py_None);
75   }
76 }
77 
mkspent(struct spwd * p)78 static PyObject *mkspent(struct spwd *p)
79 {
80     int setIndex = 0;
81     PyObject *v = PyStructSequence_New(&StructSpwdType);
82     if (v == NULL)
83         return NULL;
84 
85 #define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val))
86 #define SETS(i,val) sets(v, i, val)
87 
88     SETS(setIndex++, p->sp_namp);
89     SETS(setIndex++, p->sp_pwdp);
90     SETI(setIndex++, p->sp_lstchg);
91     SETI(setIndex++, p->sp_min);
92     SETI(setIndex++, p->sp_max);
93     SETI(setIndex++, p->sp_warn);
94     SETI(setIndex++, p->sp_inact);
95     SETI(setIndex++, p->sp_expire);
96     SETI(setIndex++, p->sp_flag);
97     SETS(setIndex++, p->sp_namp); /* Backward compatibility for sp_nam */
98     SETS(setIndex++, p->sp_pwdp); /* Backward compatibility for sp_pwd */
99 
100 #undef SETS
101 #undef SETI
102 
103     if (PyErr_Occurred()) {
104         Py_DECREF(v);
105         return NULL;
106     }
107 
108     return v;
109 }
110 
111 #endif  /* HAVE_GETSPNAM || HAVE_GETSPENT */
112 
113 
114 #ifdef HAVE_GETSPNAM
115 
116 /*[clinic input]
117 spwd.getspnam
118 
119     arg: unicode
120     /
121 
122 Return the shadow password database entry for the given user name.
123 
124 See `help(spwd)` for more on shadow password database entries.
125 [clinic start generated code]*/
126 
127 static PyObject *
spwd_getspnam_impl(PyObject * module,PyObject * arg)128 spwd_getspnam_impl(PyObject *module, PyObject *arg)
129 /*[clinic end generated code: output=701250cf57dc6ebe input=dd89429e6167a00f]*/
130 {
131     char *name;
132     struct spwd *p;
133     PyObject *bytes, *retval = NULL;
134 
135     if ((bytes = PyUnicode_EncodeFSDefault(arg)) == NULL)
136         return NULL;
137     /* check for embedded null bytes */
138     if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1)
139         goto out;
140     if ((p = getspnam(name)) == NULL) {
141         if (errno != 0)
142             PyErr_SetFromErrno(PyExc_OSError);
143         else
144             PyErr_SetString(PyExc_KeyError, "getspnam(): name not found");
145         goto out;
146     }
147     retval = mkspent(p);
148 out:
149     Py_DECREF(bytes);
150     return retval;
151 }
152 
153 #endif /* HAVE_GETSPNAM */
154 
155 #ifdef HAVE_GETSPENT
156 
157 /*[clinic input]
158 spwd.getspall
159 
160 Return a list of all available shadow password database entries, in arbitrary order.
161 
162 See `help(spwd)` for more on shadow password database entries.
163 [clinic start generated code]*/
164 
165 static PyObject *
spwd_getspall_impl(PyObject * module)166 spwd_getspall_impl(PyObject *module)
167 /*[clinic end generated code: output=4fda298d6bf6d057 input=b2c84b7857d622bd]*/
168 {
169     PyObject *d;
170     struct spwd *p;
171     if ((d = PyList_New(0)) == NULL)
172         return NULL;
173     setspent();
174     while ((p = getspent()) != NULL) {
175         PyObject *v = mkspent(p);
176         if (v == NULL || PyList_Append(d, v) != 0) {
177             Py_XDECREF(v);
178             Py_DECREF(d);
179             endspent();
180             return NULL;
181         }
182         Py_DECREF(v);
183     }
184     endspent();
185     return d;
186 }
187 
188 #endif /* HAVE_GETSPENT */
189 
190 static PyMethodDef spwd_methods[] = {
191 #ifdef HAVE_GETSPNAM
192     SPWD_GETSPNAM_METHODDEF
193 #endif
194 #ifdef HAVE_GETSPENT
195     SPWD_GETSPALL_METHODDEF
196 #endif
197     {NULL,              NULL}           /* sentinel */
198 };
199 
200 
201 
202 static struct PyModuleDef spwdmodule = {
203     PyModuleDef_HEAD_INIT,
204     "spwd",
205     spwd__doc__,
206     -1,
207     spwd_methods,
208     NULL,
209     NULL,
210     NULL,
211     NULL
212 };
213 
214 PyMODINIT_FUNC
PyInit_spwd(void)215 PyInit_spwd(void)
216 {
217     PyObject *m;
218     m=PyModule_Create(&spwdmodule);
219     if (m == NULL)
220         return NULL;
221     if (!initialized) {
222         if (PyStructSequence_InitType2(&StructSpwdType,
223                                        &struct_spwd_type_desc) < 0)
224             return NULL;
225     }
226     Py_INCREF((PyObject *) &StructSpwdType);
227     PyModule_AddObject(m, "struct_spwd", (PyObject *) &StructSpwdType);
228     initialized = 1;
229     return m;
230 }
231