nismodule.c 9.49 KB
Newer Older
1 2 3
/***********************************************************
    Written by:
	Fred Gansevles <Fred.Gansevles@cs.utwente.nl>
4
	B&O group,
5 6 7 8 9 10 11 12
	Faculteit der Informatica,
	Universiteit Twente,
	Enschede,
	the Netherlands.
******************************************************************/

/* NIS module implementation */

Barry Warsaw's avatar
Barry Warsaw committed
13
#include "Python.h"
14 15 16 17 18

#include <sys/time.h>
#include <sys/types.h>
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
19
#include <rpcsvc/ypclnt.h>
20

21 22
#ifdef __sgi
/* This is missing from rpcsvc/ypclnt.h */
23
extern int yp_get_default_domain(char **);
24 25
#endif

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
PyDoc_STRVAR(get_default_domain__doc__, 
"get_default_domain() -> str\n\
Corresponds to the C library yp_get_default_domain() call, returning\n\
the default NIS domain.\n");

PyDoc_STRVAR(match__doc__,
"match(key, map, domain = defaultdomain)\n\
Corresponds to the C library yp_match() call, returning the value of\n\
key in the given map. Optionally domain can be specified but it\n\
defaults to the system default domain.\n");

PyDoc_STRVAR(cat__doc__,
"cat(map, domain = defaultdomain)\n\
Returns the entire map as a dictionary. Optionally domain can be\n\
specified but it defaults to the system default domain.\n");

PyDoc_STRVAR(maps__doc__,
"maps(domain = defaultdomain)\n\
Returns an array of all available NIS maps within a domain. If domain\n\
is not specified it defaults to the system default domain.\n");

Barry Warsaw's avatar
Barry Warsaw committed
47
static PyObject *NisError;
48

Barry Warsaw's avatar
Barry Warsaw committed
49
static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
50
nis_error (int err)
51
{
Barry Warsaw's avatar
Barry Warsaw committed
52
	PyErr_SetString(NisError, yperr_string(err));
53 54 55
	return NULL;
}

56 57 58
static struct nis_map {
	char *alias;
	char *map;
59
	int  fix;
60
} aliases [] = {
61 62 63 64 65 66 67 68 69
	{"passwd",	"passwd.byname",	0},
	{"group",	"group.byname",		0},
	{"networks",	"networks.byaddr",	0},
	{"hosts",	"hosts.byname",		0},
	{"protocols",	"protocols.bynumber",	0},
	{"services",	"services.byname",	0},
	{"aliases",	"mail.aliases",		1}, /* created with 'makedbm -a' */
	{"ethers",	"ethers.byname",	0},
	{0L,		0L,			0}
70 71 72
};

static char *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
73
nis_mapname (char *map, int *pfix)
74
{
75
	int i;
76

77 78 79 80 81 82 83 84 85 86 87 88
	*pfix = 0;
	for (i=0; aliases[i].alias != 0L; i++) {
		if (!strcmp (aliases[i].alias, map)) {
			*pfix = aliases[i].fix;
			return aliases[i].map;
		}
		if (!strcmp (aliases[i].map, map)) {
			*pfix = aliases[i].fix;
			return aliases[i].map;
		}
	}

89 90 91
	return map;
}

92 93 94
#ifdef __APPLE__
typedef int (*foreachfunc)(unsigned long, char *, int, char *, int, void *);
#else
95
typedef int (*foreachfunc)(int, char *, int, char *, int, char *);
96
#endif
97

98 99 100
struct ypcallback_data {
	PyObject	*dict;
	int			fix;
101
	PyThreadState *state;
102 103
};

104
static int
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
105 106
nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
             int invallen, struct ypcallback_data *indata)
107 108
{
	if (instatus == YP_TRUE) {
109 110
		PyObject *key;
		PyObject *val;
111
		int err;
112

113
		PyEval_RestoreThread(indata->state);
114
		if (indata->fix) {
115 116 117 118
		    if (inkeylen > 0 && inkey[inkeylen-1] == '\0')
			inkeylen--;
		    if (invallen > 0 && inval[invallen-1] == '\0')
			invallen--;
119
		}
120 121
		key = PyString_FromStringAndSize(inkey, inkeylen);
		val = PyString_FromStringAndSize(inval, invallen);
122 123
		if (key == NULL || val == NULL) {
			/* XXX error -- don't know how to handle */
Barry Warsaw's avatar
Barry Warsaw committed
124 125 126
			PyErr_Clear();
			Py_XDECREF(key);
			Py_XDECREF(val);
127 128
			return 1;
		}
129
		err = PyDict_SetItem(indata->dict, key, val);
Barry Warsaw's avatar
Barry Warsaw committed
130 131
		Py_DECREF(key);
		Py_DECREF(val);
132
		if (err != 0)
Barry Warsaw's avatar
Barry Warsaw committed
133
			PyErr_Clear();
134 135 136
		indata->state = PyEval_SaveThread();
		if (err != 0)
		  	return 1;
137 138 139 140 141
		return 0;
	}
	return 1;
}

Barry Warsaw's avatar
Barry Warsaw committed
142
static PyObject *
143
nis_get_default_domain (PyObject *self)
144
{
145
	char *domain;
146 147 148 149 150 151
	int err;
	PyObject *res;

	if ((err = yp_get_default_domain(&domain)) != 0)
		return nis_error(err);

152
	res = PyString_FromStringAndSize (domain, strlen(domain));
153 154 155 156 157 158 159 160
	return res;
}

static PyObject *
nis_match (PyObject *self, PyObject *args, PyObject *kwdict)
{
	char *match;
	char *domain = NULL;
161
	int keylen, len;
162 163
	char *key, *map;
	int err;
Barry Warsaw's avatar
Barry Warsaw committed
164
	PyObject *res;
165
	int fix;
166
	static char *kwlist[] = {"key", "map", "domain", NULL};
167

168 169 170
	if (!PyArg_ParseTupleAndKeywords(args, kwdict,
					 "t#s|s:match", kwlist,
					 &key, &keylen, &map, &domain))
171
		return NULL;
172
	if (!domain && ((err = yp_get_default_domain(&domain)) != 0))
173
		return nis_error(err);
174 175 176
	map = nis_mapname (map, &fix);
	if (fix)
	    keylen++;
Barry Warsaw's avatar
Barry Warsaw committed
177
	Py_BEGIN_ALLOW_THREADS
178
	err = yp_match (domain, map, key, keylen, &match, &len);
Barry Warsaw's avatar
Barry Warsaw committed
179
	Py_END_ALLOW_THREADS
180 181
	if (fix)
	    len--;
182 183
	if (err != 0)
		return nis_error(err);
184
	res = PyString_FromStringAndSize (match, len);
185 186
	free (match);
	return res;
187 188
}

Barry Warsaw's avatar
Barry Warsaw committed
189
static PyObject *
190
nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
191
{
192
	char *domain = NULL;
193 194
	char *map;
	struct ypall_callback cb;
195 196
	struct ypcallback_data data;
	PyObject *dict;
197
	int err;
198
	static char *kwlist[] = {"map", "domain", NULL};
199

200 201
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat",
				         kwlist, &map, &domain))
202
		return NULL;
203
	if (!domain && ((err = yp_get_default_domain(&domain)) != 0))
204
		return nis_error(err);
205 206
	dict = PyDict_New ();
	if (dict == NULL)
207
		return NULL;
208
	cb.foreach = (foreachfunc)nis_foreach;
209 210 211
	data.dict = dict;
	map = nis_mapname (map, &data.fix);
	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 218
		return nis_error(err);
	}
219
	return dict;
220 221
}

222 223 224 225 226 227 228 229 230 231 232
/* These should be u_long on Sun h/w but not on 64-bit h/w.
   This is not portable to machines with 16-bit ints and no prototypes */
#ifndef YPPROC_MAPLIST
#define YPPROC_MAPLIST	11
#endif
#ifndef YPPROG
#define YPPROG		100004
#endif
#ifndef YPVERS
#define YPVERS		2
#endif
233 234 235 236 237

typedef char *domainname;
typedef char *mapname;

enum nisstat {
Barry Warsaw's avatar
Barry Warsaw committed
238 239 240 241 242 243 244 245 246 247 248
	NIS_TRUE = 1,
	NIS_NOMORE = 2,
	NIS_FALSE = 0,
	NIS_NOMAP = -1,
	NIS_NODOM = -2,
	NIS_NOKEY = -3,
	NIS_BADOP = -4,
	NIS_BADDB = -5,
	NIS_YPERR = -6,
	NIS_BADARGS = -7,
	NIS_VERS = -8
249 250 251 252
};
typedef enum nisstat nisstat;

struct nismaplist {
Barry Warsaw's avatar
Barry Warsaw committed
253 254
	mapname map;
	struct nismaplist *next;
255 256 257 258 259 260 261 262 263 264 265 266 267
};
typedef struct nismaplist nismaplist;

struct nisresp_maplist {
	nisstat stat;
	nismaplist *maps;
};
typedef struct nisresp_maplist nisresp_maplist;

static struct timeval TIMEOUT = { 25, 0 };

static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
268
nis_xdr_domainname(XDR *xdrs, domainname *objp)
269
{
Barry Warsaw's avatar
Barry Warsaw committed
270 271 272 273
	if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
		return (FALSE);
	}
	return (TRUE);
274 275 276 277
}

static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
278
nis_xdr_mapname(XDR *xdrs, mapname *objp)
279
{
Barry Warsaw's avatar
Barry Warsaw committed
280 281 282 283
	if (!xdr_string(xdrs, objp, YPMAXMAP)) {
		return (FALSE);
	}
	return (TRUE);
284 285 286 287
}

static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
288
nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
289
{
Barry Warsaw's avatar
Barry Warsaw committed
290 291 292 293
	if (!nis_xdr_mapname(xdrs, &objp->map)) {
		return (FALSE);
	}
	if (!xdr_pointer(xdrs, (char **)&objp->next,
Guido van Rossum's avatar
Guido van Rossum committed
294
			 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
Barry Warsaw's avatar
Barry Warsaw committed
295 296 297 298
	{
		return (FALSE);
	}
	return (TRUE);
299 300 301 302
}

static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
303
nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
304
{
Barry Warsaw's avatar
Barry Warsaw committed
305 306 307 308
	if (!xdr_enum(xdrs, (enum_t *)objp)) {
		return (FALSE);
	}
	return (TRUE);
309 310 311 312 313
}


static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
314
nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
315
{
Barry Warsaw's avatar
Barry Warsaw committed
316 317 318 319
	if (!nis_xdr_ypstat(xdrs, &objp->stat)) {
		return (FALSE);
	}
	if (!xdr_pointer(xdrs, (char **)&objp->maps,
Guido van Rossum's avatar
Guido van Rossum committed
320
			 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
Barry Warsaw's avatar
Barry Warsaw committed
321 322 323 324
	{
		return (FALSE);
	}
	return (TRUE);
325 326 327 328 329
}


static
nisresp_maplist *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
330
nisproc_maplist_2(domainname *argp, CLIENT *clnt)
331
{
Barry Warsaw's avatar
Barry Warsaw committed
332 333 334
	static nisresp_maplist res;

	memset(&res, 0, sizeof(res));
Guido van Rossum's avatar
Guido van Rossum committed
335 336 337 338 339
	if (clnt_call(clnt, YPPROC_MAPLIST,
		      (xdrproc_t)nis_xdr_domainname, (caddr_t)argp,
		      (xdrproc_t)nis_xdr_ypresp_maplist, (caddr_t)&res,
		      TIMEOUT) != RPC_SUCCESS)
	{
Barry Warsaw's avatar
Barry Warsaw committed
340 341 342
		return (NULL);
	}
	return (&res);
343 344 345 346
}

static
nismaplist *
347
nis_maplist (char *dom)
348
{
349
	nisresp_maplist *list;
350
	CLIENT *cl;
351
	char *server = NULL;
Barry Warsaw's avatar
Barry Warsaw committed
352
	int mapi = 0;
353

354
	while (!server && aliases[mapi].map != 0L) {
Barry Warsaw's avatar
Barry Warsaw committed
355 356 357
		yp_master (dom, aliases[mapi].map, &server);
		mapi++;
	}
358
        if (!server) {
Barry Warsaw's avatar
Barry Warsaw committed
359 360 361
            PyErr_SetString(NisError, "No NIS master found for any map");
            return NULL;
        }
362 363
	cl = clnt_create(server, YPPROG, YPVERS, "tcp");
	if (cl == NULL) {
Barry Warsaw's avatar
Barry Warsaw committed
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 373
		goto finally;

374
	free(server);
375
	return list->maps;
376 377

  finally:
378
	free(server);
379
	return NULL;
380 381
}

Barry Warsaw's avatar
Barry Warsaw committed
382
static PyObject *
383
nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
384
{
385
	char *domain = NULL;
386
	nismaplist *maps;
Barry Warsaw's avatar
Barry Warsaw committed
387
	PyObject *list;
388
        int err;
389
	static char *kwlist[] = {"domain", NULL};
390

391 392 393 394 395 396 397 398 399
	if (!PyArg_ParseTupleAndKeywords(args, kwdict,
					 "|s:maps", kwlist, &domain))
		return NULL;
	if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) {
		nis_error(err);
		return NULL;
	}

	if ((maps = nis_maplist (domain)) == NULL)
400
		return NULL;
Barry Warsaw's avatar
Barry Warsaw committed
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)
Barry Warsaw's avatar
Barry Warsaw committed
406 407
		{
			Py_DECREF(list);
408 409 410
			list = NULL;
			break;
		}
411
		Py_DECREF(str);
412 413
	}
	/* XXX Shouldn't we free the list of maps now? */
414 415 416
	return list;
}

Barry Warsaw's avatar
Barry Warsaw committed
417
static PyMethodDef nis_methods[] = {
418 419 420 421 422 423 424 425 426 427 428 429 430
	{"match",		(PyCFunction)nis_match,
					METH_VARARGS | METH_KEYWORDS,
					match__doc__},
	{"cat",			(PyCFunction)nis_cat,
					METH_VARARGS | METH_KEYWORDS,
					cat__doc__},
	{"maps",		(PyCFunction)nis_maps,
					METH_VARARGS | METH_KEYWORDS,
					maps__doc__},
	{"get_default_domain",	(PyCFunction)nis_get_default_domain,
 					METH_NOARGS,
					get_default_domain__doc__},
	{NULL,			NULL}		 /* Sentinel */
431 432
};

433 434 435
PyDoc_STRVAR(nis__doc__,
"This module contains functions for accessing NIS maps.\n");

436
void
437
initnis (void)
438
{
Barry Warsaw's avatar
Barry Warsaw committed
439
	PyObject *m, *d;
440
	m = Py_InitModule3("nis", nis_methods, nis__doc__);
441 442
	if (m == NULL)
		return;
Barry Warsaw's avatar
Barry Warsaw committed
443
	d = PyModule_GetDict(m);
444 445 446
	NisError = PyErr_NewException("nis.error", NULL, NULL);
	if (NisError != NULL)
		PyDict_SetItemString(d, "error", NisError);
447
}