blob: acea30679bf5ec987ededd2efdeacaf927ff0ac9 [file] [log] [blame]
Martin v. Löwisc3001752005-01-23 09:27:24 +00001
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"
Martin v. Löwisc3001752005-01-23 09:27:24 +00007
8#include <sys/types.h>
9#ifdef HAVE_SHADOW_H
10#include <shadow.h>
11#endif
12
Brett Cannon52d67ef2014-08-22 14:01:56 -040013#include "clinic/spwdmodule.c.h"
14
Brett Cannon20cf6dd2014-08-22 13:59:24 -040015/*[clinic input]
Brett Cannon20cf6dd2014-08-22 13:59:24 -040016module spwd
17[clinic start generated code]*/
Serhiy Storchaka1009bf12015-04-03 23:53:51 +030018/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c0b841b90a6a07ce]*/
Martin v. Löwisc3001752005-01-23 09:27:24 +000019
20PyDoc_STRVAR(spwd__doc__,
21"This module provides access to the Unix shadow password database.\n\
22It is available on various Unix versions.\n\
23\n\
24Shadow password database entries are reported as 9-tuples of type struct_spwd,\n\
25containing the following items from the password database (see `<shadow.h>'):\n\
26sp_namp, sp_pwdp, sp_lstchg, sp_min, sp_max, sp_warn, sp_inact, sp_expire, sp_flag.\n\
27The sp_namp and sp_pwdp are strings, the rest are integers.\n\
28An exception is raised if the entry asked for cannot be found.\n\
29You have to be root to be able to use this module.");
30
31
32#if defined(HAVE_GETSPNAM) || defined(HAVE_GETSPENT)
33
34static PyStructSequence_Field struct_spwd_type_fields[] = {
R David Murraybd90d092013-11-03 19:54:05 -050035 {"sp_namp", "login name"},
36 {"sp_pwdp", "encrypted password"},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000037 {"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"},
R David Murraybd90d092013-11-03 19:54:05 -050041 {"sp_inact", "#days after pw expires until account is disabled"},
42 {"sp_expire", "#days since 1970-01-01 when account expires"},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000043 {"sp_flag", "reserved"},
R David Murraybd90d092013-11-03 19:54:05 -050044 {"sp_nam", "login name; deprecated"}, /* Backward compatibility */
45 {"sp_pwd", "encrypted password; deprecated"}, /* Backward compatibility */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000046 {0}
Martin v. Löwisc3001752005-01-23 09:27:24 +000047};
48
49PyDoc_STRVAR(struct_spwd__doc__,
50"spwd.struct_spwd: Results from getsp*() routines.\n\n\
51This object may be accessed either as a 9-tuple of\n\
R David Murraybd90d092013-11-03 19:54:05 -050052 (sp_namp,sp_pwdp,sp_lstchg,sp_min,sp_max,sp_warn,sp_inact,sp_expire,sp_flag)\n\
Martin v. Löwisc3001752005-01-23 09:27:24 +000053or via the object attributes as named in the above tuple.");
54
55static PyStructSequence_Desc struct_spwd_type_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000056 "spwd.struct_spwd",
57 struct_spwd__doc__,
58 struct_spwd_type_fields,
59 9,
Martin v. Löwisc3001752005-01-23 09:27:24 +000060};
61
Christian Heimesbf9d70a2020-11-19 10:54:03 +010062typedef struct {
63 PyTypeObject *StructSpwdType;
64} spwdmodulestate;
Martin v. Löwisc3001752005-01-23 09:27:24 +000065
Christian Heimesbf9d70a2020-11-19 10:54:03 +010066static inline spwdmodulestate*
67get_spwd_state(PyObject *module)
68{
69 void *state = PyModule_GetState(module);
70 assert(state != NULL);
71 return (spwdmodulestate *)state;
72}
73
74static struct PyModuleDef spwdmodule;
Martin v. Löwisc3001752005-01-23 09:27:24 +000075
76static void
Neal Norwitzeb8b3a62007-08-24 23:26:23 +000077sets(PyObject *v, int i, const char* val)
Martin v. Löwisc3001752005-01-23 09:27:24 +000078{
Martin v. Löwisb6a748b2009-05-29 15:23:17 +000079 if (val) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000080 PyObject *o = PyUnicode_DecodeFSDefault(val);
81 PyStructSequence_SET_ITEM(v, i, o);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +000082 } else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000083 PyStructSequence_SET_ITEM(v, i, Py_None);
84 Py_INCREF(Py_None);
Martin v. Löwisc3001752005-01-23 09:27:24 +000085 }
86}
87
Christian Heimesbf9d70a2020-11-19 10:54:03 +010088static PyObject *mkspent(PyObject *module, struct spwd *p)
Martin v. Löwisc3001752005-01-23 09:27:24 +000089{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 int setIndex = 0;
Christian Heimesbf9d70a2020-11-19 10:54:03 +010091 PyObject *v = PyStructSequence_New(get_spwd_state(module)->StructSpwdType);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000092 if (v == NULL)
93 return NULL;
Martin v. Löwisc3001752005-01-23 09:27:24 +000094
Christian Heimes217cfd12007-12-02 14:31:20 +000095#define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val))
Martin v. Löwisc3001752005-01-23 09:27:24 +000096#define SETS(i,val) sets(v, i, val)
97
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098 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);
R David Murraybd90d092013-11-03 19:54:05 -0500107 SETS(setIndex++, p->sp_namp); /* Backward compatibility for sp_nam */
108 SETS(setIndex++, p->sp_pwdp); /* Backward compatibility for sp_pwd */
Martin v. Löwisc3001752005-01-23 09:27:24 +0000109
110#undef SETS
111#undef SETI
112
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 if (PyErr_Occurred()) {
114 Py_DECREF(v);
115 return NULL;
116 }
Martin v. Löwisc3001752005-01-23 09:27:24 +0000117
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000118 return v;
Martin v. Löwisc3001752005-01-23 09:27:24 +0000119}
120
121#endif /* HAVE_GETSPNAM || HAVE_GETSPENT */
122
123
124#ifdef HAVE_GETSPNAM
125
Brett Cannon20cf6dd2014-08-22 13:59:24 -0400126/*[clinic input]
127spwd.getspnam
Martin v. Löwisc3001752005-01-23 09:27:24 +0000128
Brett Cannon20cf6dd2014-08-22 13:59:24 -0400129 arg: unicode
130 /
131
132Return the shadow password database entry for the given user name.
133
134See `help(spwd)` for more on shadow password database entries.
135[clinic start generated code]*/
136
137static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300138spwd_getspnam_impl(PyObject *module, PyObject *arg)
139/*[clinic end generated code: output=701250cf57dc6ebe input=dd89429e6167a00f]*/
Martin v. Löwisc3001752005-01-23 09:27:24 +0000140{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000141 char *name;
142 struct spwd *p;
Brett Cannon20cf6dd2014-08-22 13:59:24 -0400143 PyObject *bytes, *retval = NULL;
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000144
Victor Stinnerae6265f2010-05-15 16:27:27 +0000145 if ((bytes = PyUnicode_EncodeFSDefault(arg)) == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000146 return NULL;
Serhiy Storchakaf7eae0a2017-06-28 08:30:06 +0300147 /* check for embedded null bytes */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000148 if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1)
149 goto out;
150 if ((p = getspnam(name)) == NULL) {
Berker Peksag3c3d7f42016-03-19 11:44:17 +0200151 if (errno != 0)
152 PyErr_SetFromErrno(PyExc_OSError);
153 else
154 PyErr_SetString(PyExc_KeyError, "getspnam(): name not found");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000155 goto out;
156 }
Christian Heimesbf9d70a2020-11-19 10:54:03 +0100157 retval = mkspent(module, p);
Martin v. Löwisb6a748b2009-05-29 15:23:17 +0000158out:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 Py_DECREF(bytes);
160 return retval;
Martin v. Löwisc3001752005-01-23 09:27:24 +0000161}
162
Neal Norwitz62679962005-01-24 23:33:50 +0000163#endif /* HAVE_GETSPNAM */
164
165#ifdef HAVE_GETSPENT
166
Brett Cannon20cf6dd2014-08-22 13:59:24 -0400167/*[clinic input]
168spwd.getspall
169
170Return a list of all available shadow password database entries, in arbitrary order.
171
172See `help(spwd)` for more on shadow password database entries.
173[clinic start generated code]*/
Martin v. Löwisc3001752005-01-23 09:27:24 +0000174
Martin v. Löwisc3001752005-01-23 09:27:24 +0000175static PyObject *
Serhiy Storchaka1a2b24f2016-07-07 17:35:15 +0300176spwd_getspall_impl(PyObject *module)
177/*[clinic end generated code: output=4fda298d6bf6d057 input=b2c84b7857d622bd]*/
Martin v. Löwisc3001752005-01-23 09:27:24 +0000178{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000179 PyObject *d;
180 struct spwd *p;
181 if ((d = PyList_New(0)) == NULL)
182 return NULL;
183 setspent();
184 while ((p = getspent()) != NULL) {
Christian Heimesbf9d70a2020-11-19 10:54:03 +0100185 PyObject *v = mkspent(module, p);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 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;
Martin v. Löwisc3001752005-01-23 09:27:24 +0000196}
197
198#endif /* HAVE_GETSPENT */
199
200static PyMethodDef spwd_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201#ifdef HAVE_GETSPNAM
Brett Cannon20cf6dd2014-08-22 13:59:24 -0400202 SPWD_GETSPNAM_METHODDEF
Martin v. Löwisc3001752005-01-23 09:27:24 +0000203#endif
204#ifdef HAVE_GETSPENT
Brett Cannon20cf6dd2014-08-22 13:59:24 -0400205 SPWD_GETSPALL_METHODDEF
Martin v. Löwisc3001752005-01-23 09:27:24 +0000206#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207 {NULL, NULL} /* sentinel */
Martin v. Löwisc3001752005-01-23 09:27:24 +0000208};
209
Christian Heimesbf9d70a2020-11-19 10:54:03 +0100210static int
211spwdmodule_exec(PyObject *module)
212{
213 spwdmodulestate *state = get_spwd_state(module);
Martin v. Löwisc3001752005-01-23 09:27:24 +0000214
Christian Heimesbf9d70a2020-11-19 10:54:03 +0100215 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
225static PyModuleDef_Slot spwdmodule_slots[] = {
226 {Py_mod_exec, spwdmodule_exec},
227 {0, NULL}
228};
229
230static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
231 Py_VISIT(get_spwd_state(m)->StructSpwdType);
232 return 0;
233}
234
235static int spwdmodule_clear(PyObject *m) {
236 Py_CLEAR(get_spwd_state(m)->StructSpwdType);
237 return 0;
238}
239
240static void spwdmodule_free(void *m) {
241 spwdmodule_clear((PyObject *)m);
242}
Martin v. Löwis1a214512008-06-11 05:26:20 +0000243
244static struct PyModuleDef spwdmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 PyModuleDef_HEAD_INIT,
Christian Heimesbf9d70a2020-11-19 10:54:03 +0100246 .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,
Martin v. Löwis1a214512008-06-11 05:26:20 +0000254};
255
Martin v. Löwisc3001752005-01-23 09:27:24 +0000256PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000257PyInit_spwd(void)
Martin v. Löwisc3001752005-01-23 09:27:24 +0000258{
Christian Heimesbf9d70a2020-11-19 10:54:03 +0100259 return PyModuleDef_Init(&spwdmodule);
Martin v. Löwisc3001752005-01-23 09:27:24 +0000260}