PageRenderTime 65ms CodeModel.GetById 38ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/Modules/nismodule.c

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