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] 11module pwd 12[clinic start generated code]*/ 13/*[clinic end generated code: output=da39a3ee5e6b4b0d input=60f628ef356b97b6]*/ 14 15static 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 26PyDoc_STRVAR(struct_passwd__doc__, 27"pwd.struct_passwd: Results from getpw*() routines.\n\n\ 28This 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\ 30or via the object attributes as named in the above tuple."); 31 32static PyStructSequence_Desc struct_pwd_type_desc = { 33 "pwd.struct_passwd", 34 struct_passwd__doc__, 35 struct_pwd_type_fields, 36 7, 37}; 38 39PyDoc_STRVAR(pwd__doc__, 40"This module provides access to the Unix password database.\n\ 41It is available on all Unix versions.\n\ 42\n\ 43Password database entries are reported as 7-tuples containing the following\n\ 44items from the password database (see `<pwd.h>'), in order:\n\ 45pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell.\n\ 46The uid and gid items are integers, all others are strings. An\n\ 47exception is raised if the entry asked for cannot be found."); 48 49 50typedef struct { 51 PyTypeObject *StructPwdType; 52} pwdmodulestate; 53 54static inline pwdmodulestate* 55get_pwd_state(PyObject *module) 56{ 57 void *state = PyModule_GetState(module); 58 assert(state != NULL); 59 return (pwdmodulestate *)state; 60} 61 62static struct PyModuleDef pwdmodule; 63 64#define DEFAULT_BUFFER_SIZE 1024 65 66static void 67sets(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 79static PyObject * 80mkpwent(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] 116pwd.getpwuid 117 118 uidobj: object 119 / 120 121Return the password database entry for the given numeric user ID. 122 123See `help(pwd)` for more on password database entries. 124[clinic start generated code]*/ 125 126static PyObject * 127pwd_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] 201pwd.getpwnam 202 203 name: unicode 204 / 205 206Return the password database entry for the given user name. 207 208See `help(pwd)` for more on password database entries. 209[clinic start generated code]*/ 210 211static PyObject * 212pwd_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); 274out: 275 PyMem_RawFree(buf); 276 Py_DECREF(bytes); 277 return retval; 278} 279 280#ifdef HAVE_GETPWENT 281/*[clinic input] 282pwd.getpwall 283 284Return a list of all available password database entries, in arbitrary order. 285 286See help(pwd) for more on password database entries. 287[clinic start generated code]*/ 288 289static PyObject * 290pwd_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 313static 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 322static int 323pwdmodule_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 337static PyModuleDef_Slot pwdmodule_slots[] = { 338 {Py_mod_exec, pwdmodule_exec}, 339 {0, NULL} 340}; 341 342static int pwdmodule_traverse(PyObject *m, visitproc visit, void *arg) { 343 Py_VISIT(get_pwd_state(m)->StructPwdType); 344 return 0; 345} 346static int pwdmodule_clear(PyObject *m) { 347 Py_CLEAR(get_pwd_state(m)->StructPwdType); 348 return 0; 349} 350static void pwdmodule_free(void *m) { 351 pwdmodule_clear((PyObject *)m); 352} 353 354static struct PyModuleDef pwdmodule = { 355 PyModuleDef_HEAD_INIT, 356 .m_name = "pwd", 357 .m_doc = pwd__doc__, 358 .m_size = sizeof(pwdmodulestate), 359 .m_methods = pwd_methods, 360 .m_slots = pwdmodule_slots, 361 .m_traverse = pwdmodule_traverse, 362 .m_clear = pwdmodule_clear, 363 .m_free = pwdmodule_free, 364}; 365 366 367PyMODINIT_FUNC 368PyInit_pwd(void) 369{ 370 return PyModuleDef_Init(&pwdmodule); 371} 372