Home | History | Annotate | Download | only in Modules
      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
     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 
     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 *
    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     if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1)
    138         goto out;
    139     if ((p = getspnam(name)) == NULL) {
    140         if (errno != 0)
    141             PyErr_SetFromErrno(PyExc_OSError);
    142         else
    143             PyErr_SetString(PyExc_KeyError, "getspnam(): name not found");
    144         goto out;
    145     }
    146     retval = mkspent(p);
    147 out:
    148     Py_DECREF(bytes);
    149     return retval;
    150 }
    151 
    152 #endif /* HAVE_GETSPNAM */
    153 
    154 #ifdef HAVE_GETSPENT
    155 
    156 /*[clinic input]
    157 spwd.getspall
    158 
    159 Return a list of all available shadow password database entries, in arbitrary order.
    160 
    161 See `help(spwd)` for more on shadow password database entries.
    162 [clinic start generated code]*/
    163 
    164 static PyObject *
    165 spwd_getspall_impl(PyObject *module)
    166 /*[clinic end generated code: output=4fda298d6bf6d057 input=b2c84b7857d622bd]*/
    167 {
    168     PyObject *d;
    169     struct spwd *p;
    170     if ((d = PyList_New(0)) == NULL)
    171         return NULL;
    172     setspent();
    173     while ((p = getspent()) != NULL) {
    174         PyObject *v = mkspent(p);
    175         if (v == NULL || PyList_Append(d, v) != 0) {
    176             Py_XDECREF(v);
    177             Py_DECREF(d);
    178             endspent();
    179             return NULL;
    180         }
    181         Py_DECREF(v);
    182     }
    183     endspent();
    184     return d;
    185 }
    186 
    187 #endif /* HAVE_GETSPENT */
    188 
    189 static PyMethodDef spwd_methods[] = {
    190 #ifdef HAVE_GETSPNAM
    191     SPWD_GETSPNAM_METHODDEF
    192 #endif
    193 #ifdef HAVE_GETSPENT
    194     SPWD_GETSPALL_METHODDEF
    195 #endif
    196     {NULL,              NULL}           /* sentinel */
    197 };
    198 
    199 
    200 
    201 static struct PyModuleDef spwdmodule = {
    202     PyModuleDef_HEAD_INIT,
    203     "spwd",
    204     spwd__doc__,
    205     -1,
    206     spwd_methods,
    207     NULL,
    208     NULL,
    209     NULL,
    210     NULL
    211 };
    212 
    213 PyMODINIT_FUNC
    214 PyInit_spwd(void)
    215 {
    216     PyObject *m;
    217     m=PyModule_Create(&spwdmodule);
    218     if (m == NULL)
    219         return NULL;
    220     if (!initialized) {
    221         if (PyStructSequence_InitType2(&StructSpwdType,
    222                                        &struct_spwd_type_desc) < 0)
    223             return NULL;
    224     }
    225     Py_INCREF((PyObject *) &StructSpwdType);
    226     PyModule_AddObject(m, "struct_spwd", (PyObject *) &StructSpwdType);
    227     initialized = 1;
    228     return m;
    229 }
    230