| |
| /* UNIX shadow password file access module */ |
| /* A lot of code has been taken from pwdmodule.c */ |
| /* For info also see http://www.unixpapa.com/incnote/passwd.html */ |
| |
| #include "Python.h" |
| |
| #include <sys/types.h> |
| #ifdef HAVE_SHADOW_H |
| #include <shadow.h> |
| #endif |
| |
| #include "clinic/spwdmodule.c.h" |
| |
| /*[clinic input] |
| module spwd |
| [clinic start generated code]*/ |
| /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c0b841b90a6a07ce]*/ |
| |
| PyDoc_STRVAR(spwd__doc__, |
| "This module provides access to the Unix shadow password database.\n\ |
| It is available on various Unix versions.\n\ |
| \n\ |
| Shadow password database entries are reported as 9-tuples of type struct_spwd,\n\ |
| containing the following items from the password database (see `<shadow.h>'):\n\ |
| sp_namp, sp_pwdp, sp_lstchg, sp_min, sp_max, sp_warn, sp_inact, sp_expire, sp_flag.\n\ |
| The sp_namp and sp_pwdp are strings, the rest are integers.\n\ |
| An exception is raised if the entry asked for cannot be found.\n\ |
| You have to be root to be able to use this module."); |
| |
| |
| #if defined(HAVE_GETSPNAM) || defined(HAVE_GETSPENT) |
| |
| static PyStructSequence_Field struct_spwd_type_fields[] = { |
| {"sp_namp", "login name"}, |
| {"sp_pwdp", "encrypted password"}, |
| {"sp_lstchg", "date of last change"}, |
| {"sp_min", "min #days between changes"}, |
| {"sp_max", "max #days between changes"}, |
| {"sp_warn", "#days before pw expires to warn user about it"}, |
| {"sp_inact", "#days after pw expires until account is disabled"}, |
| {"sp_expire", "#days since 1970-01-01 when account expires"}, |
| {"sp_flag", "reserved"}, |
| {"sp_nam", "login name; deprecated"}, /* Backward compatibility */ |
| {"sp_pwd", "encrypted password; deprecated"}, /* Backward compatibility */ |
| {0} |
| }; |
| |
| PyDoc_STRVAR(struct_spwd__doc__, |
| "spwd.struct_spwd: Results from getsp*() routines.\n\n\ |
| This object may be accessed either as a 9-tuple of\n\ |
| (sp_namp,sp_pwdp,sp_lstchg,sp_min,sp_max,sp_warn,sp_inact,sp_expire,sp_flag)\n\ |
| or via the object attributes as named in the above tuple."); |
| |
| static PyStructSequence_Desc struct_spwd_type_desc = { |
| "spwd.struct_spwd", |
| struct_spwd__doc__, |
| struct_spwd_type_fields, |
| 9, |
| }; |
| |
| typedef struct { |
| PyTypeObject *StructSpwdType; |
| } spwdmodulestate; |
| |
| static inline spwdmodulestate* |
| get_spwd_state(PyObject *module) |
| { |
| void *state = PyModule_GetState(module); |
| assert(state != NULL); |
| return (spwdmodulestate *)state; |
| } |
| |
| static struct PyModuleDef spwdmodule; |
| |
| static void |
| sets(PyObject *v, int i, const char* val) |
| { |
| if (val) { |
| PyObject *o = PyUnicode_DecodeFSDefault(val); |
| PyStructSequence_SET_ITEM(v, i, o); |
| } else { |
| PyStructSequence_SET_ITEM(v, i, Py_None); |
| Py_INCREF(Py_None); |
| } |
| } |
| |
| static PyObject *mkspent(PyObject *module, struct spwd *p) |
| { |
| int setIndex = 0; |
| PyObject *v = PyStructSequence_New(get_spwd_state(module)->StructSpwdType); |
| if (v == NULL) |
| return NULL; |
| |
| #define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val)) |
| #define SETS(i,val) sets(v, i, val) |
| |
| SETS(setIndex++, p->sp_namp); |
| SETS(setIndex++, p->sp_pwdp); |
| SETI(setIndex++, p->sp_lstchg); |
| SETI(setIndex++, p->sp_min); |
| SETI(setIndex++, p->sp_max); |
| SETI(setIndex++, p->sp_warn); |
| SETI(setIndex++, p->sp_inact); |
| SETI(setIndex++, p->sp_expire); |
| SETI(setIndex++, p->sp_flag); |
| SETS(setIndex++, p->sp_namp); /* Backward compatibility for sp_nam */ |
| SETS(setIndex++, p->sp_pwdp); /* Backward compatibility for sp_pwd */ |
| |
| #undef SETS |
| #undef SETI |
| |
| if (PyErr_Occurred()) { |
| Py_DECREF(v); |
| return NULL; |
| } |
| |
| return v; |
| } |
| |
| #endif /* HAVE_GETSPNAM || HAVE_GETSPENT */ |
| |
| |
| #ifdef HAVE_GETSPNAM |
| |
| /*[clinic input] |
| spwd.getspnam |
| |
| arg: unicode |
| / |
| |
| Return the shadow password database entry for the given user name. |
| |
| See `help(spwd)` for more on shadow password database entries. |
| [clinic start generated code]*/ |
| |
| static PyObject * |
| spwd_getspnam_impl(PyObject *module, PyObject *arg) |
| /*[clinic end generated code: output=701250cf57dc6ebe input=dd89429e6167a00f]*/ |
| { |
| char *name; |
| struct spwd *p; |
| PyObject *bytes, *retval = NULL; |
| |
| if ((bytes = PyUnicode_EncodeFSDefault(arg)) == NULL) |
| return NULL; |
| /* check for embedded null bytes */ |
| if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1) |
| goto out; |
| if ((p = getspnam(name)) == NULL) { |
| if (errno != 0) |
| PyErr_SetFromErrno(PyExc_OSError); |
| else |
| PyErr_SetString(PyExc_KeyError, "getspnam(): name not found"); |
| goto out; |
| } |
| retval = mkspent(module, p); |
| out: |
| Py_DECREF(bytes); |
| return retval; |
| } |
| |
| #endif /* HAVE_GETSPNAM */ |
| |
| #ifdef HAVE_GETSPENT |
| |
| /*[clinic input] |
| spwd.getspall |
| |
| Return a list of all available shadow password database entries, in arbitrary order. |
| |
| See `help(spwd)` for more on shadow password database entries. |
| [clinic start generated code]*/ |
| |
| static PyObject * |
| spwd_getspall_impl(PyObject *module) |
| /*[clinic end generated code: output=4fda298d6bf6d057 input=b2c84b7857d622bd]*/ |
| { |
| PyObject *d; |
| struct spwd *p; |
| if ((d = PyList_New(0)) == NULL) |
| return NULL; |
| setspent(); |
| while ((p = getspent()) != NULL) { |
| PyObject *v = mkspent(module, p); |
| if (v == NULL || PyList_Append(d, v) != 0) { |
| Py_XDECREF(v); |
| Py_DECREF(d); |
| endspent(); |
| return NULL; |
| } |
| Py_DECREF(v); |
| } |
| endspent(); |
| return d; |
| } |
| |
| #endif /* HAVE_GETSPENT */ |
| |
| static PyMethodDef spwd_methods[] = { |
| #ifdef HAVE_GETSPNAM |
| SPWD_GETSPNAM_METHODDEF |
| #endif |
| #ifdef HAVE_GETSPENT |
| SPWD_GETSPALL_METHODDEF |
| #endif |
| {NULL, NULL} /* sentinel */ |
| }; |
| |
| static int |
| spwdmodule_exec(PyObject *module) |
| { |
| spwdmodulestate *state = get_spwd_state(module); |
| |
| state->StructSpwdType = PyStructSequence_NewType(&struct_spwd_type_desc); |
| if (state->StructSpwdType == NULL) { |
| return -1; |
| } |
| if (PyModule_AddType(module, state->StructSpwdType) < 0) { |
| return -1; |
| } |
| return 0; |
| } |
| |
| static PyModuleDef_Slot spwdmodule_slots[] = { |
| {Py_mod_exec, spwdmodule_exec}, |
| {0, NULL} |
| }; |
| |
| static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) { |
| Py_VISIT(get_spwd_state(m)->StructSpwdType); |
| return 0; |
| } |
| |
| static int spwdmodule_clear(PyObject *m) { |
| Py_CLEAR(get_spwd_state(m)->StructSpwdType); |
| return 0; |
| } |
| |
| static void spwdmodule_free(void *m) { |
| spwdmodule_clear((PyObject *)m); |
| } |
| |
| static struct PyModuleDef spwdmodule = { |
| PyModuleDef_HEAD_INIT, |
| .m_name = "spwd", |
| .m_doc = spwd__doc__, |
| .m_size = sizeof(spwdmodulestate), |
| .m_methods = spwd_methods, |
| .m_slots = spwdmodule_slots, |
| .m_traverse = spwdmodule_traverse, |
| .m_clear = spwdmodule_clear, |
| .m_free = spwdmodule_free, |
| }; |
| |
| PyMODINIT_FUNC |
| PyInit_spwd(void) |
| { |
| return PyModuleDef_Init(&spwdmodule); |
| } |