Line data Source code
1 : /***********************************************************
2 : Written by:
3 : Fred Gansevles <Fred.Gansevles@cs.utwente.nl>
4 : B&O group,
5 : Faculteit der Informatica,
6 : Universiteit Twente,
7 : Enschede,
8 : the Netherlands.
9 : ******************************************************************/
10 :
11 : /* NIS module implementation */
12 :
13 : #include "Python.h"
14 :
15 : #include <stdlib.h> // free()
16 : #include <sys/time.h>
17 : #include <sys/types.h>
18 : #include <rpc/rpc.h>
19 : #include <rpcsvc/yp_prot.h>
20 : #include <rpcsvc/ypclnt.h>
21 :
22 : #ifdef __sgi
23 : /* This is missing from rpcsvc/ypclnt.h */
24 : extern int yp_get_default_domain(char **);
25 : #endif
26 :
27 : PyDoc_STRVAR(get_default_domain__doc__,
28 : "get_default_domain() -> str\n\
29 : Corresponds to the C library yp_get_default_domain() call, returning\n\
30 : the default NIS domain.\n");
31 :
32 : PyDoc_STRVAR(match__doc__,
33 : "match(key, map, domain = defaultdomain)\n\
34 : Corresponds to the C library yp_match() call, returning the value of\n\
35 : key in the given map. Optionally domain can be specified but it\n\
36 : defaults to the system default domain.\n");
37 :
38 : PyDoc_STRVAR(cat__doc__,
39 : "cat(map, domain = defaultdomain)\n\
40 : Returns the entire map as a dictionary. Optionally domain can be\n\
41 : specified but it defaults to the system default domain.\n");
42 :
43 : PyDoc_STRVAR(maps__doc__,
44 : "maps(domain = defaultdomain)\n\
45 : Returns an array of all available NIS maps within a domain. If domain\n\
46 : is not specified it defaults to the system default domain.\n");
47 :
48 : typedef struct {
49 : PyObject *nis_error;
50 : } nis_state;
51 :
52 : static inline nis_state*
53 65 : get_nis_state(PyObject *module)
54 : {
55 65 : void *state = PyModule_GetState(module);
56 65 : assert(state != NULL);
57 65 : return (nis_state *)state;
58 : }
59 :
60 : static int
61 4 : nis_clear(PyObject *m)
62 : {
63 4 : Py_CLEAR(get_nis_state(m)->nis_error);
64 4 : return 0;
65 : }
66 :
67 : static int
68 28 : nis_traverse(PyObject *m, visitproc visit, void *arg)
69 : {
70 28 : Py_VISIT(get_nis_state(m)->nis_error);
71 28 : return 0;
72 : }
73 :
74 : static void
75 2 : nis_free(void *m)
76 : {
77 2 : nis_clear((PyObject *) m);
78 2 : }
79 :
80 : static PyObject *
81 1 : nis_error(nis_state *state, int err)
82 : {
83 1 : PyErr_SetString(state->nis_error, yperr_string(err));
84 1 : return NULL;
85 : }
86 :
87 : static struct nis_map {
88 : char *alias;
89 : char *map;
90 : int fix;
91 : } aliases [] = {
92 : {"passwd", "passwd.byname", 0},
93 : {"group", "group.byname", 0},
94 : {"networks", "networks.byaddr", 0},
95 : {"hosts", "hosts.byname", 0},
96 : {"protocols", "protocols.bynumber", 0},
97 : {"services", "services.byname", 0},
98 : {"aliases", "mail.aliases", 1}, /* created with 'makedbm -a' */
99 : {"ethers", "ethers.byname", 0},
100 : {0L, 0L, 0}
101 : };
102 :
103 : static char *
104 0 : nis_mapname(char *map, int *pfix)
105 : {
106 : int i;
107 :
108 0 : *pfix = 0;
109 0 : for (i=0; aliases[i].alias != 0L; i++) {
110 0 : if (!strcmp (aliases[i].alias, map) || !strcmp (aliases[i].map, map)) {
111 0 : *pfix = aliases[i].fix;
112 0 : return aliases[i].map;
113 : }
114 : }
115 :
116 0 : return map;
117 : }
118 :
119 : #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
120 : typedef int (*foreachfunc)(unsigned long, char *, int, char *, int, void *);
121 : #else
122 : typedef int (*foreachfunc)(int, char *, int, char *, int, char *);
123 : #endif
124 :
125 : struct ypcallback_data {
126 : PyObject *dict;
127 : int fix;
128 : PyThreadState *state;
129 : };
130 :
131 : static int
132 0 : nis_foreach(int instatus, char *inkey, int inkeylen, char *inval,
133 : int invallen, struct ypcallback_data *indata)
134 : {
135 0 : if (instatus == YP_TRUE) {
136 : PyObject *key;
137 : PyObject *val;
138 : int err;
139 :
140 0 : PyEval_RestoreThread(indata->state);
141 0 : if (indata->fix) {
142 0 : if (inkeylen > 0 && inkey[inkeylen-1] == '\0')
143 0 : inkeylen--;
144 0 : if (invallen > 0 && inval[invallen-1] == '\0')
145 0 : invallen--;
146 : }
147 0 : key = PyUnicode_DecodeFSDefaultAndSize(inkey, inkeylen);
148 0 : val = PyUnicode_DecodeFSDefaultAndSize(inval, invallen);
149 0 : if (key == NULL || val == NULL) {
150 : /* XXX error -- don't know how to handle */
151 0 : PyErr_Clear();
152 0 : Py_XDECREF(key);
153 0 : Py_XDECREF(val);
154 0 : indata->state = PyEval_SaveThread();
155 0 : return 1;
156 : }
157 0 : err = PyDict_SetItem(indata->dict, key, val);
158 0 : Py_DECREF(key);
159 0 : Py_DECREF(val);
160 0 : if (err != 0)
161 0 : PyErr_Clear();
162 0 : indata->state = PyEval_SaveThread();
163 0 : if (err != 0)
164 0 : return 1;
165 0 : return 0;
166 : }
167 0 : return 1;
168 : }
169 :
170 : static PyObject *
171 0 : nis_get_default_domain(PyObject *module, PyObject *Py_UNUSED(ignored))
172 : {
173 : char *domain;
174 : int err;
175 : PyObject *res;
176 0 : nis_state *state = get_nis_state(module);
177 0 : if ((err = yp_get_default_domain(&domain)) != 0) {
178 0 : return nis_error(state, err);
179 : }
180 :
181 0 : res = PyUnicode_FromStringAndSize (domain, strlen(domain));
182 0 : return res;
183 : }
184 :
185 : static PyObject *
186 0 : nis_match(PyObject *module, PyObject *args, PyObject *kwdict)
187 : {
188 : char *match;
189 0 : char *domain = NULL;
190 : Py_ssize_t keylen;
191 : int len;
192 : char *key, *map;
193 : int err;
194 : PyObject *ukey, *bkey, *res;
195 : int fix;
196 : static char *kwlist[] = {"key", "map", "domain", NULL};
197 :
198 0 : if (!PyArg_ParseTupleAndKeywords(args, kwdict,
199 : "Us|s:match", kwlist,
200 : &ukey, &map, &domain)) {
201 0 : return NULL;
202 : }
203 0 : if ((bkey = PyUnicode_EncodeFSDefault(ukey)) == NULL) {
204 0 : return NULL;
205 : }
206 : /* check for embedded null bytes */
207 0 : if (PyBytes_AsStringAndSize(bkey, &key, &keylen) == -1) {
208 0 : Py_DECREF(bkey);
209 0 : return NULL;
210 : }
211 :
212 0 : nis_state *state = get_nis_state(module);
213 0 : if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) {
214 0 : Py_DECREF(bkey);
215 0 : return nis_error(state, err);
216 : }
217 0 : map = nis_mapname (map, &fix);
218 0 : if (fix)
219 0 : keylen++;
220 0 : Py_BEGIN_ALLOW_THREADS
221 0 : err = yp_match (domain, map, key, keylen, &match, &len);
222 0 : Py_END_ALLOW_THREADS
223 0 : Py_DECREF(bkey);
224 0 : if (fix)
225 0 : len--;
226 0 : if (err != 0) {
227 0 : return nis_error(state, err);
228 : }
229 0 : res = PyUnicode_DecodeFSDefaultAndSize(match, len);
230 0 : free (match);
231 0 : return res;
232 : }
233 :
234 : static PyObject *
235 0 : nis_cat(PyObject *module, PyObject *args, PyObject *kwdict)
236 : {
237 0 : char *domain = NULL;
238 : char *map;
239 : struct ypall_callback cb;
240 : struct ypcallback_data data;
241 : PyObject *dict;
242 : int err;
243 : static char *kwlist[] = {"map", "domain", NULL};
244 :
245 0 : if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat",
246 : kwlist, &map, &domain)) {
247 0 : return NULL;
248 : }
249 0 : nis_state *state = get_nis_state(module);
250 0 : if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) {
251 0 : return nis_error(state, err);
252 : }
253 0 : dict = PyDict_New ();
254 0 : if (dict == NULL)
255 0 : return NULL;
256 0 : cb.foreach = (foreachfunc)nis_foreach;
257 0 : data.dict = dict;
258 0 : map = nis_mapname (map, &data.fix);
259 0 : cb.data = (char *)&data;
260 0 : data.state = PyEval_SaveThread();
261 0 : err = yp_all (domain, map, &cb);
262 0 : PyEval_RestoreThread(data.state);
263 0 : if (err != 0) {
264 0 : Py_DECREF(dict);
265 0 : return nis_error(state, err);
266 : }
267 0 : return dict;
268 : }
269 :
270 : /* These should be u_long on Sun h/w but not on 64-bit h/w.
271 : This is not portable to machines with 16-bit ints and no prototypes */
272 : #ifndef YPPROC_MAPLIST
273 : #define YPPROC_MAPLIST 11
274 : #endif
275 : #ifndef YPPROG
276 : #define YPPROG 100004
277 : #endif
278 : #ifndef YPVERS
279 : #define YPVERS 2
280 : #endif
281 :
282 : typedef char *domainname;
283 : typedef char *mapname;
284 :
285 : enum nisstat {
286 : NIS_TRUE = 1,
287 : NIS_NOMORE = 2,
288 : NIS_FALSE = 0,
289 : NIS_NOMAP = -1,
290 : NIS_NODOM = -2,
291 : NIS_NOKEY = -3,
292 : NIS_BADOP = -4,
293 : NIS_BADDB = -5,
294 : NIS_YPERR = -6,
295 : NIS_BADARGS = -7,
296 : NIS_VERS = -8
297 : };
298 : typedef enum nisstat nisstat;
299 :
300 : struct nismaplist {
301 : mapname map;
302 : struct nismaplist *next;
303 : };
304 : typedef struct nismaplist nismaplist;
305 :
306 : struct nisresp_maplist {
307 : nisstat stat;
308 : nismaplist *maps;
309 : };
310 : typedef struct nisresp_maplist nisresp_maplist;
311 :
312 : static struct timeval TIMEOUT = { 25, 0 };
313 :
314 : static
315 : bool_t
316 0 : nis_xdr_domainname(XDR *xdrs, domainname *objp)
317 : {
318 0 : if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
319 0 : return (FALSE);
320 : }
321 0 : return (TRUE);
322 : }
323 :
324 : static
325 : bool_t
326 0 : nis_xdr_mapname(XDR *xdrs, mapname *objp)
327 : {
328 0 : if (!xdr_string(xdrs, objp, YPMAXMAP)) {
329 0 : return (FALSE);
330 : }
331 0 : return (TRUE);
332 : }
333 :
334 : static
335 : bool_t
336 0 : nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
337 : {
338 0 : if (!nis_xdr_mapname(xdrs, &objp->map)) {
339 0 : return (FALSE);
340 : }
341 0 : if (!xdr_pointer(xdrs, (char **)&objp->next,
342 : sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
343 : {
344 0 : return (FALSE);
345 : }
346 0 : return (TRUE);
347 : }
348 :
349 : static
350 : bool_t
351 0 : nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
352 : {
353 0 : if (!xdr_enum(xdrs, (enum_t *)objp)) {
354 0 : return (FALSE);
355 : }
356 0 : return (TRUE);
357 : }
358 :
359 :
360 : static
361 : bool_t
362 0 : nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
363 : {
364 0 : if (!nis_xdr_ypstat(xdrs, &objp->stat)) {
365 0 : return (FALSE);
366 : }
367 0 : if (!xdr_pointer(xdrs, (char **)&objp->maps,
368 : sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
369 : {
370 0 : return (FALSE);
371 : }
372 0 : return (TRUE);
373 : }
374 :
375 :
376 : static
377 : nisresp_maplist *
378 0 : nisproc_maplist_2(domainname *argp, CLIENT *clnt)
379 : {
380 : static nisresp_maplist res;
381 :
382 0 : memset(&res, 0, sizeof(res));
383 0 : if (clnt_call(clnt, YPPROC_MAPLIST,
384 : (xdrproc_t)nis_xdr_domainname, (caddr_t)argp,
385 : (xdrproc_t)nis_xdr_ypresp_maplist, (caddr_t)&res,
386 : TIMEOUT) != RPC_SUCCESS)
387 : {
388 0 : return (NULL);
389 : }
390 0 : return (&res);
391 : }
392 :
393 : static
394 : nismaplist *
395 0 : nis_maplist(nis_state *state, char *dom)
396 : {
397 : nisresp_maplist *list;
398 : CLIENT *cl;
399 0 : char *server = NULL;
400 0 : int mapi = 0;
401 :
402 0 : while (!server && aliases[mapi].map != 0L) {
403 0 : yp_master (dom, aliases[mapi].map, &server);
404 0 : mapi++;
405 : }
406 0 : if (!server) {
407 0 : PyErr_SetString(state->nis_error, "No NIS master found for any map");
408 0 : return NULL;
409 : }
410 0 : cl = clnt_create(server, YPPROG, YPVERS, "tcp");
411 0 : if (cl == NULL) {
412 0 : PyErr_SetString(state->nis_error, clnt_spcreateerror(server));
413 0 : goto finally;
414 : }
415 0 : list = nisproc_maplist_2 (&dom, cl);
416 0 : clnt_destroy(cl);
417 0 : if (list == NULL)
418 0 : goto finally;
419 0 : if (list->stat != NIS_TRUE)
420 0 : goto finally;
421 :
422 0 : free(server);
423 0 : return list->maps;
424 :
425 0 : finally:
426 0 : free(server);
427 0 : return NULL;
428 : }
429 :
430 : static PyObject *
431 1 : nis_maps (PyObject *module, PyObject *args, PyObject *kwdict)
432 : {
433 1 : char *domain = NULL;
434 : nismaplist *maps;
435 : PyObject *list;
436 : int err;
437 : static char *kwlist[] = {"domain", NULL};
438 :
439 1 : if (!PyArg_ParseTupleAndKeywords(args, kwdict,
440 : "|s:maps", kwlist, &domain)) {
441 0 : return NULL;
442 : }
443 :
444 1 : nis_state *state = get_nis_state(module);
445 1 : if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) {
446 1 : nis_error(state, err);
447 1 : return NULL;
448 : }
449 :
450 0 : if ((maps = nis_maplist(state, domain)) == NULL) {
451 0 : return NULL;
452 : }
453 0 : if ((list = PyList_New(0)) == NULL) {
454 0 : return NULL;
455 : }
456 0 : for (; maps; maps = maps->next) {
457 0 : PyObject *str = PyUnicode_FromString(maps->map);
458 0 : if (!str || PyList_Append(list, str) < 0)
459 : {
460 0 : Py_XDECREF(str);
461 0 : Py_DECREF(list);
462 0 : list = NULL;
463 0 : break;
464 : }
465 0 : Py_DECREF(str);
466 : }
467 : /* XXX Shouldn't we free the list of maps now? */
468 0 : return list;
469 : }
470 :
471 : static PyMethodDef nis_methods[] = {
472 : {"match", _PyCFunction_CAST(nis_match),
473 : METH_VARARGS | METH_KEYWORDS,
474 : match__doc__},
475 : {"cat", _PyCFunction_CAST(nis_cat),
476 : METH_VARARGS | METH_KEYWORDS,
477 : cat__doc__},
478 : {"maps", _PyCFunction_CAST(nis_maps),
479 : METH_VARARGS | METH_KEYWORDS,
480 : maps__doc__},
481 : {"get_default_domain", nis_get_default_domain,
482 : METH_NOARGS,
483 : get_default_domain__doc__},
484 : {NULL, NULL} /* Sentinel */
485 : };
486 :
487 : static int
488 2 : nis_exec(PyObject *module)
489 : {
490 2 : nis_state* state = get_nis_state(module);
491 2 : state->nis_error = PyErr_NewException("nis.error", NULL, NULL);
492 2 : if (state->nis_error == NULL) {
493 0 : return -1;
494 : }
495 :
496 2 : Py_INCREF(state->nis_error);
497 2 : if (PyModule_AddObject(module, "error", state->nis_error) < 0) {
498 0 : Py_DECREF(state->nis_error);
499 0 : return -1;
500 : }
501 2 : return 0;
502 : }
503 :
504 : static PyModuleDef_Slot nis_slots[] = {
505 : {Py_mod_exec, nis_exec},
506 : {0, NULL}
507 : };
508 :
509 : PyDoc_STRVAR(nis__doc__,
510 : "This module contains functions for accessing NIS maps.\n");
511 :
512 : static struct PyModuleDef nismodule = {
513 : PyModuleDef_HEAD_INIT,
514 : .m_name = "nis",
515 : .m_doc = nis__doc__,
516 : .m_size = sizeof(nis_state),
517 : .m_methods = nis_methods,
518 : .m_traverse = nis_traverse,
519 : .m_clear = nis_clear,
520 : .m_free = nis_free,
521 : .m_slots = nis_slots,
522 : };
523 :
524 : PyMODINIT_FUNC
525 2 : PyInit_nis(void)
526 : {
527 2 : if (PyErr_WarnEx(PyExc_DeprecationWarning,
528 : "'nis' is deprecated and slated for removal in "
529 : "Python 3.13",
530 : 7)) {
531 0 : return NULL;
532 : }
533 2 : return PyModuleDef_Init(&nismodule);
534 : }
|