1 2/* UNIX group file access module */ 3 4#include "Python.h" 5#include "posixmodule.h" 6 7#include <grp.h> 8 9#include "clinic/grpmodule.c.h" 10/*[clinic input] 11module grp 12[clinic start generated code]*/ 13/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cade63f2ed1bd9f8]*/ 14 15static PyStructSequence_Field struct_group_type_fields[] = { 16 {"gr_name", "group name"}, 17 {"gr_passwd", "password"}, 18 {"gr_gid", "group id"}, 19 {"gr_mem", "group members"}, 20 {0} 21}; 22 23PyDoc_STRVAR(struct_group__doc__, 24"grp.struct_group: Results from getgr*() routines.\n\n\ 25This object may be accessed either as a tuple of\n\ 26 (gr_name,gr_passwd,gr_gid,gr_mem)\n\ 27or via the object attributes as named in the above tuple.\n"); 28 29static PyStructSequence_Desc struct_group_type_desc = { 30 "grp.struct_group", 31 struct_group__doc__, 32 struct_group_type_fields, 33 4, 34}; 35 36 37typedef struct { 38 PyTypeObject *StructGrpType; 39} grpmodulestate; 40 41static inline grpmodulestate* 42get_grp_state(PyObject *module) 43{ 44 void *state = PyModule_GetState(module); 45 assert(state != NULL); 46 return (grpmodulestate *)state; 47} 48 49static struct PyModuleDef grpmodule; 50 51#define DEFAULT_BUFFER_SIZE 1024 52 53static PyObject * 54mkgrent(PyObject *module, struct group *p) 55{ 56 int setIndex = 0; 57 PyObject *v, *w; 58 char **member; 59 60 v = PyStructSequence_New(get_grp_state(module)->StructGrpType); 61 if (v == NULL) 62 return NULL; 63 64 if ((w = PyList_New(0)) == NULL) { 65 Py_DECREF(v); 66 return NULL; 67 } 68 for (member = p->gr_mem; *member != NULL; member++) { 69 PyObject *x = PyUnicode_DecodeFSDefault(*member); 70 if (x == NULL || PyList_Append(w, x) != 0) { 71 Py_XDECREF(x); 72 Py_DECREF(w); 73 Py_DECREF(v); 74 return NULL; 75 } 76 Py_DECREF(x); 77 } 78 79#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val) 80 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_name)); 81 if (p->gr_passwd) 82 SET(setIndex++, PyUnicode_DecodeFSDefault(p->gr_passwd)); 83 else { 84 SET(setIndex++, Py_None); 85 Py_INCREF(Py_None); 86 } 87 SET(setIndex++, _PyLong_FromGid(p->gr_gid)); 88 SET(setIndex++, w); 89#undef SET 90 91 if (PyErr_Occurred()) { 92 Py_DECREF(v); 93 return NULL; 94 } 95 96 return v; 97} 98 99/*[clinic input] 100grp.getgrgid 101 102 id: object 103 104Return the group database entry for the given numeric group ID. 105 106If id is not valid, raise KeyError. 107[clinic start generated code]*/ 108 109static PyObject * 110grp_getgrgid_impl(PyObject *module, PyObject *id) 111/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/ 112{ 113 PyObject *retval = NULL; 114 int nomem = 0; 115 char *buf = NULL, *buf2 = NULL; 116 gid_t gid; 117 struct group *p; 118 119 if (!_Py_Gid_Converter(id, &gid)) { 120 return NULL; 121 } 122#ifdef HAVE_GETGRGID_R 123 int status; 124 Py_ssize_t bufsize; 125 /* Note: 'grp' will be used via pointer 'p' on getgrgid_r success. */ 126 struct group grp; 127 128 Py_BEGIN_ALLOW_THREADS 129 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); 130 if (bufsize == -1) { 131 bufsize = DEFAULT_BUFFER_SIZE; 132 } 133 134 while (1) { 135 buf2 = PyMem_RawRealloc(buf, bufsize); 136 if (buf2 == NULL) { 137 p = NULL; 138 nomem = 1; 139 break; 140 } 141 buf = buf2; 142 status = getgrgid_r(gid, &grp, buf, bufsize, &p); 143 if (status != 0) { 144 p = NULL; 145 } 146 if (p != NULL || status != ERANGE) { 147 break; 148 } 149 if (bufsize > (PY_SSIZE_T_MAX >> 1)) { 150 nomem = 1; 151 break; 152 } 153 bufsize <<= 1; 154 } 155 156 Py_END_ALLOW_THREADS 157#else 158 p = getgrgid(gid); 159#endif 160 if (p == NULL) { 161 PyMem_RawFree(buf); 162 if (nomem == 1) { 163 return PyErr_NoMemory(); 164 } 165 PyObject *gid_obj = _PyLong_FromGid(gid); 166 if (gid_obj == NULL) 167 return NULL; 168 PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %S", gid_obj); 169 Py_DECREF(gid_obj); 170 return NULL; 171 } 172 retval = mkgrent(module, p); 173#ifdef HAVE_GETGRGID_R 174 PyMem_RawFree(buf); 175#endif 176 return retval; 177} 178 179/*[clinic input] 180grp.getgrnam 181 182 name: unicode 183 184Return the group database entry for the given group name. 185 186If name is not valid, raise KeyError. 187[clinic start generated code]*/ 188 189static PyObject * 190grp_getgrnam_impl(PyObject *module, PyObject *name) 191/*[clinic end generated code: output=67905086f403c21c input=08ded29affa3c863]*/ 192{ 193 char *buf = NULL, *buf2 = NULL, *name_chars; 194 int nomem = 0; 195 struct group *p; 196 PyObject *bytes, *retval = NULL; 197 198 if ((bytes = PyUnicode_EncodeFSDefault(name)) == NULL) 199 return NULL; 200 /* check for embedded null bytes */ 201 if (PyBytes_AsStringAndSize(bytes, &name_chars, NULL) == -1) 202 goto out; 203#ifdef HAVE_GETGRNAM_R 204 int status; 205 Py_ssize_t bufsize; 206 /* Note: 'grp' will be used via pointer 'p' on getgrnam_r success. */ 207 struct group grp; 208 209 Py_BEGIN_ALLOW_THREADS 210 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); 211 if (bufsize == -1) { 212 bufsize = DEFAULT_BUFFER_SIZE; 213 } 214 215 while(1) { 216 buf2 = PyMem_RawRealloc(buf, bufsize); 217 if (buf2 == NULL) { 218 p = NULL; 219 nomem = 1; 220 break; 221 } 222 buf = buf2; 223 status = getgrnam_r(name_chars, &grp, buf, bufsize, &p); 224 if (status != 0) { 225 p = NULL; 226 } 227 if (p != NULL || status != ERANGE) { 228 break; 229 } 230 if (bufsize > (PY_SSIZE_T_MAX >> 1)) { 231 nomem = 1; 232 break; 233 } 234 bufsize <<= 1; 235 } 236 237 Py_END_ALLOW_THREADS 238#else 239 p = getgrnam(name_chars); 240#endif 241 if (p == NULL) { 242 if (nomem == 1) { 243 PyErr_NoMemory(); 244 } 245 else { 246 PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name); 247 } 248 goto out; 249 } 250 retval = mkgrent(module, p); 251out: 252 PyMem_RawFree(buf); 253 Py_DECREF(bytes); 254 return retval; 255} 256 257/*[clinic input] 258grp.getgrall 259 260Return a list of all available group entries, in arbitrary order. 261 262An entry whose name starts with '+' or '-' represents an instruction 263to use YP/NIS and may not be accessible via getgrnam or getgrgid. 264[clinic start generated code]*/ 265 266static PyObject * 267grp_getgrall_impl(PyObject *module) 268/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/ 269{ 270 PyObject *d; 271 struct group *p; 272 273 if ((d = PyList_New(0)) == NULL) 274 return NULL; 275 setgrent(); 276 while ((p = getgrent()) != NULL) { 277 PyObject *v = mkgrent(module, p); 278 if (v == NULL || PyList_Append(d, v) != 0) { 279 Py_XDECREF(v); 280 Py_DECREF(d); 281 endgrent(); 282 return NULL; 283 } 284 Py_DECREF(v); 285 } 286 endgrent(); 287 return d; 288} 289 290static PyMethodDef grp_methods[] = { 291 GRP_GETGRGID_METHODDEF 292 GRP_GETGRNAM_METHODDEF 293 GRP_GETGRALL_METHODDEF 294 {NULL, NULL} 295}; 296 297PyDoc_STRVAR(grp__doc__, 298"Access to the Unix group database.\n\ 299\n\ 300Group entries are reported as 4-tuples containing the following fields\n\ 301from the group database, in order:\n\ 302\n\ 303 gr_name - name of the group\n\ 304 gr_passwd - group password (encrypted); often empty\n\ 305 gr_gid - numeric ID of the group\n\ 306 gr_mem - list of members\n\ 307\n\ 308The gid is an integer, name and password are strings. (Note that most\n\ 309users are not explicitly listed as members of the groups they are in\n\ 310according to the password database. Check both databases to get\n\ 311complete membership information.)"); 312 313static int 314grpmodule_exec(PyObject *module) 315{ 316 grpmodulestate *state = get_grp_state(module); 317 318 state->StructGrpType = PyStructSequence_NewType(&struct_group_type_desc); 319 if (state->StructGrpType == NULL) { 320 return -1; 321 } 322 if (PyModule_AddType(module, state->StructGrpType) < 0) { 323 return -1; 324 } 325 return 0; 326} 327 328static PyModuleDef_Slot grpmodule_slots[] = { 329 {Py_mod_exec, grpmodule_exec}, 330 {0, NULL} 331}; 332 333static int grpmodule_traverse(PyObject *m, visitproc visit, void *arg) { 334 Py_VISIT(get_grp_state(m)->StructGrpType); 335 return 0; 336} 337 338static int grpmodule_clear(PyObject *m) { 339 Py_CLEAR(get_grp_state(m)->StructGrpType); 340 return 0; 341} 342 343static void grpmodule_free(void *m) { 344 grpmodule_clear((PyObject *)m); 345} 346 347static struct PyModuleDef grpmodule = { 348 PyModuleDef_HEAD_INIT, 349 .m_name = "grp", 350 .m_doc = grp__doc__, 351 .m_size = sizeof(grpmodulestate), 352 .m_methods = grp_methods, 353 .m_slots = grpmodule_slots, 354 .m_traverse = grpmodule_traverse, 355 .m_clear = grpmodule_clear, 356 .m_free = grpmodule_free, 357}; 358 359PyMODINIT_FUNC 360PyInit_grp(void) 361{ 362 return PyModuleDef_Init(&grpmodule); 363} 364