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