(root)/
Python-3.11.7/
Modules/
spwdmodule.c
       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  typedef struct {
      63      PyTypeObject *StructSpwdType;
      64  } spwdmodulestate;
      65  
      66  static inline spwdmodulestate*
      67  get_spwd_state(PyObject *module)
      68  {
      69      void *state = PyModule_GetState(module);
      70      assert(state != NULL);
      71      return (spwdmodulestate *)state;
      72  }
      73  
      74  static struct PyModuleDef spwdmodule;
      75  
      76  static void
      77  sets(PyObject *v, int i, const char* val)
      78  {
      79    if (val) {
      80        PyObject *o = PyUnicode_DecodeFSDefault(val);
      81        PyStructSequence_SET_ITEM(v, i, o);
      82    } else {
      83        PyStructSequence_SET_ITEM(v, i, Py_None);
      84        Py_INCREF(Py_None);
      85    }
      86  }
      87  
      88  static PyObject *mkspent(PyObject *module, struct spwd *p)
      89  {
      90      int setIndex = 0;
      91      PyObject *v = PyStructSequence_New(get_spwd_state(module)->StructSpwdType);
      92      if (v == NULL)
      93          return NULL;
      94  
      95  #define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyLong_FromLong((long) val))
      96  #define SETS(i,val) sets(v, i, val)
      97  
      98      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);
     107      SETS(setIndex++, p->sp_namp); /* Backward compatibility for sp_nam */
     108      SETS(setIndex++, p->sp_pwdp); /* Backward compatibility for sp_pwd */
     109  
     110  #undef SETS
     111  #undef SETI
     112  
     113      if (PyErr_Occurred()) {
     114          Py_DECREF(v);
     115          return NULL;
     116      }
     117  
     118      return v;
     119  }
     120  
     121  #endif  /* HAVE_GETSPNAM || HAVE_GETSPENT */
     122  
     123  
     124  #ifdef HAVE_GETSPNAM
     125  
     126  /*[clinic input]
     127  spwd.getspnam
     128  
     129      arg: unicode
     130      /
     131  
     132  Return the shadow password database entry for the given user name.
     133  
     134  See `help(spwd)` for more on shadow password database entries.
     135  [clinic start generated code]*/
     136  
     137  static PyObject *
     138  spwd_getspnam_impl(PyObject *module, PyObject *arg)
     139  /*[clinic end generated code: output=701250cf57dc6ebe input=dd89429e6167a00f]*/
     140  {
     141      char *name;
     142      struct spwd *p;
     143      PyObject *bytes, *retval = NULL;
     144  
     145      if ((bytes = PyUnicode_EncodeFSDefault(arg)) == NULL)
     146          return NULL;
     147      /* check for embedded null bytes */
     148      if (PyBytes_AsStringAndSize(bytes, &name, NULL) == -1)
     149          goto out;
     150      if ((p = getspnam(name)) == NULL) {
     151          if (errno != 0)
     152              PyErr_SetFromErrno(PyExc_OSError);
     153          else
     154              PyErr_SetString(PyExc_KeyError, "getspnam(): name not found");
     155          goto out;
     156      }
     157      retval = mkspent(module, p);
     158  out:
     159      Py_DECREF(bytes);
     160      return retval;
     161  }
     162  
     163  #endif /* HAVE_GETSPNAM */
     164  
     165  #ifdef HAVE_GETSPENT
     166  
     167  /*[clinic input]
     168  spwd.getspall
     169  
     170  Return a list of all available shadow password database entries, in arbitrary order.
     171  
     172  See `help(spwd)` for more on shadow password database entries.
     173  [clinic start generated code]*/
     174  
     175  static PyObject *
     176  spwd_getspall_impl(PyObject *module)
     177  /*[clinic end generated code: output=4fda298d6bf6d057 input=b2c84b7857d622bd]*/
     178  {
     179      PyObject *d;
     180      struct spwd *p;
     181      if ((d = PyList_New(0)) == NULL)
     182          return NULL;
     183      setspent();
     184      while ((p = getspent()) != NULL) {
     185          PyObject *v = mkspent(module, p);
     186          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;
     196  }
     197  
     198  #endif /* HAVE_GETSPENT */
     199  
     200  static PyMethodDef spwd_methods[] = {
     201  #ifdef HAVE_GETSPNAM
     202      SPWD_GETSPNAM_METHODDEF
     203  #endif
     204  #ifdef HAVE_GETSPENT
     205      SPWD_GETSPALL_METHODDEF
     206  #endif
     207      {NULL,              NULL}           /* sentinel */
     208  };
     209  
     210  static int
     211  spwdmodule_exec(PyObject *module)
     212  {
     213      spwdmodulestate *state = get_spwd_state(module);
     214  
     215      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  
     225  static PyModuleDef_Slot spwdmodule_slots[] = {
     226      {Py_mod_exec, spwdmodule_exec},
     227      {0, NULL}
     228  };
     229  
     230  static int spwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
     231      Py_VISIT(get_spwd_state(m)->StructSpwdType);
     232      return 0;
     233  }
     234  
     235  static int spwdmodule_clear(PyObject *m) {
     236      Py_CLEAR(get_spwd_state(m)->StructSpwdType);
     237      return 0;
     238  }
     239  
     240  static void spwdmodule_free(void *m) {
     241      spwdmodule_clear((PyObject *)m);
     242  }
     243  
     244  static struct PyModuleDef spwdmodule = {
     245      PyModuleDef_HEAD_INIT,
     246      .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,
     254  };
     255  
     256  PyMODINIT_FUNC
     257  PyInit_spwd(void)
     258  {
     259      if (PyErr_WarnEx(PyExc_DeprecationWarning,
     260                       "'spwd' is deprecated and slated for removal in "
     261                       "Python 3.13",
     262                       7)) {
     263          return NULL;
     264      }
     265  
     266      return PyModuleDef_Init(&spwdmodule);
     267  }