(root)/
Python-3.12.0/
Modules/
pwdmodule.c
       1  
       2  /* UNIX password file access module */
       3  
       4  #include "Python.h"
       5  #include "posixmodule.h"
       6  
       7  #include <pwd.h>
       8  
       9  #include "clinic/pwdmodule.c.h"
      10  /*[clinic input]
      11  module pwd
      12  [clinic start generated code]*/
      13  /*[clinic end generated code: output=da39a3ee5e6b4b0d input=60f628ef356b97b6]*/
      14  
      15  static PyStructSequence_Field struct_pwd_type_fields[] = {
      16      {"pw_name", "user name"},
      17      {"pw_passwd", "password"},
      18      {"pw_uid", "user id"},
      19      {"pw_gid", "group id"},
      20      {"pw_gecos", "real name"},
      21      {"pw_dir", "home directory"},
      22      {"pw_shell", "shell program"},
      23      {0}
      24  };
      25  
      26  PyDoc_STRVAR(struct_passwd__doc__,
      27  "pwd.struct_passwd: Results from getpw*() routines.\n\n\
      28  This object may be accessed either as a tuple of\n\
      29    (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell)\n\
      30  or via the object attributes as named in the above tuple.");
      31  
      32  static PyStructSequence_Desc struct_pwd_type_desc = {
      33      "pwd.struct_passwd",
      34      struct_passwd__doc__,
      35      struct_pwd_type_fields,
      36      7,
      37  };
      38  
      39  PyDoc_STRVAR(pwd__doc__,
      40  "This module provides access to the Unix password database.\n\
      41  It is available on all Unix versions.\n\
      42  \n\
      43  Password database entries are reported as 7-tuples containing the following\n\
      44  items from the password database (see `<pwd.h>'), in order:\n\
      45  pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell.\n\
      46  The uid and gid items are integers, all others are strings. An\n\
      47  exception is raised if the entry asked for cannot be found.");
      48  
      49  
      50  typedef struct {
      51      PyTypeObject *StructPwdType;
      52  } pwdmodulestate;
      53  
      54  static inline pwdmodulestate*
      55  get_pwd_state(PyObject *module)
      56  {
      57      void *state = PyModule_GetState(module);
      58      assert(state != NULL);
      59      return (pwdmodulestate *)state;
      60  }
      61  
      62  static struct PyModuleDef pwdmodule;
      63  
      64  #define DEFAULT_BUFFER_SIZE 1024
      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    }
      73    else {
      74        PyStructSequence_SET_ITEM(v, i, Py_None);
      75        Py_INCREF(Py_None);
      76    }
      77  }
      78  
      79  static PyObject *
      80  mkpwent(PyObject *module, struct passwd *p)
      81  {
      82      int setIndex = 0;
      83      PyObject *v = PyStructSequence_New(get_pwd_state(module)->StructPwdType);
      84      if (v == NULL)
      85          return NULL;
      86  
      87  #define SETS(i,val) sets(v, i, val)
      88  
      89      SETS(setIndex++, p->pw_name);
      90  #if defined(HAVE_STRUCT_PASSWD_PW_PASSWD) && !defined(__ANDROID__)
      91      SETS(setIndex++, p->pw_passwd);
      92  #else
      93      SETS(setIndex++, "");
      94  #endif
      95      PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromUid(p->pw_uid));
      96      PyStructSequence_SET_ITEM(v, setIndex++, _PyLong_FromGid(p->pw_gid));
      97  #if defined(HAVE_STRUCT_PASSWD_PW_GECOS)
      98      SETS(setIndex++, p->pw_gecos);
      99  #else
     100      SETS(setIndex++, "");
     101  #endif
     102      SETS(setIndex++, p->pw_dir);
     103      SETS(setIndex++, p->pw_shell);
     104  
     105  #undef SETS
     106  
     107      if (PyErr_Occurred()) {
     108          Py_XDECREF(v);
     109          return NULL;
     110      }
     111  
     112      return v;
     113  }
     114  
     115  /*[clinic input]
     116  pwd.getpwuid
     117  
     118      uidobj: object
     119      /
     120  
     121  Return the password database entry for the given numeric user ID.
     122  
     123  See `help(pwd)` for more on password database entries.
     124  [clinic start generated code]*/
     125  
     126  static PyObject *
     127  pwd_getpwuid(PyObject *module, PyObject *uidobj)
     128  /*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/
     129  {
     130      PyObject *retval = NULL;
     131      uid_t uid;
     132      int nomem = 0;
     133      struct passwd *p;
     134      char *buf = NULL, *buf2 = NULL;
     135  
     136      if (!_Py_Uid_Converter(uidobj, &uid)) {
     137          if (PyErr_ExceptionMatches(PyExc_OverflowError))
     138              PyErr_Format(PyExc_KeyError,
     139                           "getpwuid(): uid not found");
     140          return NULL;
     141      }
     142  #ifdef HAVE_GETPWUID_R
     143      int status;
     144      Py_ssize_t bufsize;
     145      /* Note: 'pwd' will be used via pointer 'p' on getpwuid_r success. */
     146      struct passwd pwd;
     147  
     148      Py_BEGIN_ALLOW_THREADS
     149      bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
     150      if (bufsize == -1) {
     151          bufsize = DEFAULT_BUFFER_SIZE;
     152      }
     153  
     154      while(1) {
     155          buf2 = PyMem_RawRealloc(buf, bufsize);
     156          if (buf2 == NULL) {
     157              p = NULL;
     158              nomem = 1;
     159              break;
     160          }
     161          buf = buf2;
     162          status = getpwuid_r(uid, &pwd, buf, bufsize, &p);
     163          if (status != 0) {
     164              p = NULL;
     165          }
     166          if (p != NULL || status != ERANGE) {
     167              break;
     168          }
     169          if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
     170              nomem = 1;
     171              break;
     172          }
     173          bufsize <<= 1;
     174      }
     175  
     176      Py_END_ALLOW_THREADS
     177  #else
     178      p = getpwuid(uid);
     179  #endif
     180      if (p == NULL) {
     181          PyMem_RawFree(buf);
     182          if (nomem == 1) {
     183              return PyErr_NoMemory();
     184          }
     185          PyObject *uid_obj = _PyLong_FromUid(uid);
     186          if (uid_obj == NULL)
     187              return NULL;
     188          PyErr_Format(PyExc_KeyError,
     189                       "getpwuid(): uid not found: %S", uid_obj);
     190          Py_DECREF(uid_obj);
     191          return NULL;
     192      }
     193      retval = mkpwent(module, p);
     194  #ifdef HAVE_GETPWUID_R
     195      PyMem_RawFree(buf);
     196  #endif
     197      return retval;
     198  }
     199  
     200  /*[clinic input]
     201  pwd.getpwnam
     202  
     203      name: unicode
     204      /
     205  
     206  Return the password database entry for the given user name.
     207  
     208  See `help(pwd)` for more on password database entries.
     209  [clinic start generated code]*/
     210  
     211  static PyObject *
     212  pwd_getpwnam_impl(PyObject *module, PyObject *name)
     213  /*[clinic end generated code: output=359ce1ddeb7a824f input=a6aeb5e3447fb9e0]*/
     214  {
     215      char *buf = NULL, *buf2 = NULL, *name_chars;
     216      int nomem = 0;
     217      struct passwd *p;
     218      PyObject *bytes, *retval = NULL;
     219  
     220      if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL)
     221          return NULL;
     222      /* check for embedded null bytes */
     223      if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1)
     224          goto out;
     225  #ifdef HAVE_GETPWNAM_R
     226      int status;
     227      Py_ssize_t bufsize;
     228      /* Note: 'pwd' will be used via pointer 'p' on getpwnam_r success. */
     229      struct passwd pwd;
     230  
     231      Py_BEGIN_ALLOW_THREADS
     232      bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
     233      if (bufsize == -1) {
     234          bufsize = DEFAULT_BUFFER_SIZE;
     235      }
     236  
     237      while(1) {
     238          buf2 = PyMem_RawRealloc(buf, bufsize);
     239          if (buf2 == NULL) {
     240              p = NULL;
     241              nomem = 1;
     242              break;
     243          }
     244          buf = buf2;
     245          status = getpwnam_r(name_chars, &pwd, buf, bufsize, &p);
     246          if (status != 0) {
     247              p = NULL;
     248          }
     249          if (p != NULL || status != ERANGE) {
     250              break;
     251          }
     252          if (bufsize > (PY_SSIZE_T_MAX >> 1)) {
     253              nomem = 1;
     254              break;
     255          }
     256          bufsize <<= 1;
     257      }
     258  
     259      Py_END_ALLOW_THREADS
     260  #else
     261      p = getpwnam(name_chars);
     262  #endif
     263      if (p == NULL) {
     264          if (nomem == 1) {
     265              PyErr_NoMemory();
     266          }
     267          else {
     268              PyErr_Format(PyExc_KeyError,
     269                           "getpwnam(): name not found: %R", name);
     270          }
     271          goto out;
     272      }
     273      retval = mkpwent(module, p);
     274  out:
     275      PyMem_RawFree(buf);
     276      Py_DECREF(bytes);
     277      return retval;
     278  }
     279  
     280  #ifdef HAVE_GETPWENT
     281  /*[clinic input]
     282  pwd.getpwall
     283  
     284  Return a list of all available password database entries, in arbitrary order.
     285  
     286  See help(pwd) for more on password database entries.
     287  [clinic start generated code]*/
     288  
     289  static PyObject *
     290  pwd_getpwall_impl(PyObject *module)
     291  /*[clinic end generated code: output=4853d2f5a0afac8a input=d7ecebfd90219b85]*/
     292  {
     293      PyObject *d;
     294      struct passwd *p;
     295      if ((d = PyList_New(0)) == NULL)
     296          return NULL;
     297      setpwent();
     298      while ((p = getpwent()) != NULL) {
     299          PyObject *v = mkpwent(module, p);
     300          if (v == NULL || PyList_Append(d, v) != 0) {
     301              Py_XDECREF(v);
     302              Py_DECREF(d);
     303              endpwent();
     304              return NULL;
     305          }
     306          Py_DECREF(v);
     307      }
     308      endpwent();
     309      return d;
     310  }
     311  #endif
     312  
     313  static PyMethodDef pwd_methods[] = {
     314      PWD_GETPWUID_METHODDEF
     315      PWD_GETPWNAM_METHODDEF
     316  #ifdef HAVE_GETPWENT
     317      PWD_GETPWALL_METHODDEF
     318  #endif
     319      {NULL,              NULL}           /* sentinel */
     320  };
     321  
     322  static int
     323  pwdmodule_exec(PyObject *module)
     324  {
     325      pwdmodulestate *state = get_pwd_state(module);
     326  
     327      state->StructPwdType = PyStructSequence_NewType(&struct_pwd_type_desc);
     328      if (state->StructPwdType == NULL) {
     329          return -1;
     330      }
     331      if (PyModule_AddType(module, state->StructPwdType) < 0) {
     332          return -1;
     333      }
     334      return 0;
     335  }
     336  
     337  static PyModuleDef_Slot pwdmodule_slots[] = {
     338      {Py_mod_exec, pwdmodule_exec},
     339      {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
     340      {0, NULL}
     341  };
     342  
     343  static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) {
     344      Py_VISIT(get_pwd_state(m)->StructPwdType);
     345      return 0;
     346  }
     347  static int pwdmodule_clear(PyObject *m) {
     348      Py_CLEAR(get_pwd_state(m)->StructPwdType);
     349      return 0;
     350  }
     351  static void pwdmodule_free(void *m) {
     352      pwdmodule_clear((PyObject *)m);
     353  }
     354  
     355  static struct PyModuleDef pwdmodule = {
     356      PyModuleDef_HEAD_INIT,
     357      .m_name = "pwd",
     358      .m_doc = pwd__doc__,
     359      .m_size = sizeof(pwdmodulestate),
     360      .m_methods = pwd_methods,
     361      .m_slots = pwdmodule_slots,
     362      .m_traverse = pwdmodule_traverse,
     363      .m_clear = pwdmodule_clear,
     364      .m_free = pwdmodule_free,
     365  };
     366  
     367  
     368  PyMODINIT_FUNC
     369  PyInit_pwd(void)
     370  {
     371      return PyModuleDef_Init(&pwdmodule);
     372  }