Branch data 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 : : 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 : : }
|