| /* 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); | |
| } |