nismodule.c 7.24 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

Barry Warsaw's avatar
Barry Warsaw committed
26
static PyObject *NisError;
27

Barry Warsaw's avatar
Barry Warsaw committed
28
static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
29
nis_error (int err)
30
{
Barry Warsaw's avatar
Barry Warsaw committed
31
	PyErr_SetString(NisError, yperr_string(err));
32 33 34
	return NULL;
}

35 36 37
static struct nis_map {
	char *alias;
	char *map;
38
	int  fix;
39
} aliases [] = {
40 41 42 43 44 45 46 47 48
	{"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}
49 50 51
};

static char *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
52
nis_mapname (char *map, int *pfix)
53
{
54
	int i;
55

56 57 58 59 60 61 62 63 64 65 66 67
	*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;
		}
	}

68 69 70
	return map;
}

71
typedef int (*foreachfunc)(int, char *, int, char *, int, char *);
72

73 74 75 76 77
struct ypcallback_data {
	PyObject	*dict;
	int			fix;
};

78
static int
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
79 80
nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
             int invallen, struct ypcallback_data *indata)
81 82
{
	if (instatus == YP_TRUE) {
83 84
		PyObject *key;
		PyObject *val;
85
		int err;
86 87 88 89 90 91 92

		if (indata->fix) {
		    inkeylen--;
		    invallen--;
		}
		key = PyString_FromStringAndSize(inkey, inkeylen);
		val = PyString_FromStringAndSize(inval, invallen);
93 94
		if (key == NULL || val == NULL) {
			/* XXX error -- don't know how to handle */
Barry Warsaw's avatar
Barry Warsaw committed
95 96 97
			PyErr_Clear();
			Py_XDECREF(key);
			Py_XDECREF(val);
98 99
			return 1;
		}
100
		err = PyDict_SetItem(indata->dict, key, val);
Barry Warsaw's avatar
Barry Warsaw committed
101 102
		Py_DECREF(key);
		Py_DECREF(val);
103
		if (err != 0) {
Barry Warsaw's avatar
Barry Warsaw committed
104
			PyErr_Clear();
105 106
			return 1;
		}
107 108 109 110 111
		return 0;
	}
	return 1;
}

Barry Warsaw's avatar
Barry Warsaw committed
112
static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
113
nis_match (PyObject *self, PyObject *args)
114
{
115 116
	char *match;
	char *domain;
117
	int keylen, len;
118 119
	char *key, *map;
	int err;
Barry Warsaw's avatar
Barry Warsaw committed
120
	PyObject *res;
121
	int fix;
122

123
	if (!PyArg_Parse(args, "(t#s)", &key, &keylen, &map))
124
		return NULL;
125 126
	if ((err = yp_get_default_domain(&domain)) != 0)
		return nis_error(err);
127 128 129
	map = nis_mapname (map, &fix);
	if (fix)
	    keylen++;
Barry Warsaw's avatar
Barry Warsaw committed
130
	Py_BEGIN_ALLOW_THREADS
131
	err = yp_match (domain, map, key, keylen, &match, &len);
Barry Warsaw's avatar
Barry Warsaw committed
132
	Py_END_ALLOW_THREADS
133 134
	if (fix)
	    len--;
135 136
	if (err != 0)
		return nis_error(err);
Barry Warsaw's avatar
Barry Warsaw committed
137
	res = PyString_FromStringAndSize (match, len);
138 139
	free (match);
	return res;
140 141
}

Barry Warsaw's avatar
Barry Warsaw committed
142
static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
143
nis_cat (PyObject *self, PyObject *args)
144
{
145 146 147
	char *domain;
	char *map;
	struct ypall_callback cb;
148 149
	struct ypcallback_data data;
	PyObject *dict;
150
	int err;
151

Barry Warsaw's avatar
Barry Warsaw committed
152
	if (!PyArg_Parse(args, "s", &map))
153
		return NULL;
154 155
	if ((err = yp_get_default_domain(&domain)) != 0)
		return nis_error(err);
156 157
	dict = PyDict_New ();
	if (dict == NULL)
158
		return NULL;
159
	cb.foreach = (foreachfunc)nis_foreach;
160 161 162
	data.dict = dict;
	map = nis_mapname (map, &data.fix);
	cb.data = (char *)&data;
Barry Warsaw's avatar
Barry Warsaw committed
163
	Py_BEGIN_ALLOW_THREADS
164
	err = yp_all (domain, map, &cb);
Barry Warsaw's avatar
Barry Warsaw committed
165
	Py_END_ALLOW_THREADS
166
	if (err != 0) {
167
		Py_DECREF(dict);
168 169
		return nis_error(err);
	}
170
	return dict;
171 172
}

173 174 175 176 177 178 179 180 181 182 183
/* 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
184 185 186 187 188

typedef char *domainname;
typedef char *mapname;

enum nisstat {
Barry Warsaw's avatar
Barry Warsaw committed
189 190 191 192 193 194 195 196 197 198 199
	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
200 201 202 203
};
typedef enum nisstat nisstat;

struct nismaplist {
Barry Warsaw's avatar
Barry Warsaw committed
204 205
	mapname map;
	struct nismaplist *next;
206 207 208 209 210 211 212 213 214 215 216 217 218
};
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
219
nis_xdr_domainname(XDR *xdrs, domainname *objp)
220
{
Barry Warsaw's avatar
Barry Warsaw committed
221 222 223 224
	if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
		return (FALSE);
	}
	return (TRUE);
225 226 227 228
}

static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
229
nis_xdr_mapname(XDR *xdrs, mapname *objp)
230
{
Barry Warsaw's avatar
Barry Warsaw committed
231 232 233 234
	if (!xdr_string(xdrs, objp, YPMAXMAP)) {
		return (FALSE);
	}
	return (TRUE);
235 236 237 238
}

static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
239
nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
240
{
Barry Warsaw's avatar
Barry Warsaw committed
241 242 243 244
	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
245
			 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
Barry Warsaw's avatar
Barry Warsaw committed
246 247 248 249
	{
		return (FALSE);
	}
	return (TRUE);
250 251 252 253
}

static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
254
nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
255
{
Barry Warsaw's avatar
Barry Warsaw committed
256 257 258 259
	if (!xdr_enum(xdrs, (enum_t *)objp)) {
		return (FALSE);
	}
	return (TRUE);
260 261 262 263 264
}


static
bool_t
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
265
nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
266
{
Barry Warsaw's avatar
Barry Warsaw committed
267 268 269 270
	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
271
			 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
Barry Warsaw's avatar
Barry Warsaw committed
272 273 274 275
	{
		return (FALSE);
	}
	return (TRUE);
276 277 278 279 280
}


static
nisresp_maplist *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
281
nisproc_maplist_2(domainname *argp, CLIENT *clnt)
282
{
Barry Warsaw's avatar
Barry Warsaw committed
283 284 285
	static nisresp_maplist res;

	memset(&res, 0, sizeof(res));
Guido van Rossum's avatar
Guido van Rossum committed
286 287 288 289 290
	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
291 292 293
		return (NULL);
	}
	return (&res);
294 295 296 297
}

static
nismaplist *
298
nis_maplist (void)
299
{
300 301
	nisresp_maplist *list;
	char *dom;
302
	CLIENT *cl;
303
	char *server = NULL;
Barry Warsaw's avatar
Barry Warsaw committed
304
	int mapi = 0;
Barry Warsaw's avatar
Barry Warsaw committed
305
        int err;
306

Barry Warsaw's avatar
Barry Warsaw committed
307 308 309 310
	if ((err = yp_get_default_domain (&dom)) != 0) {
		nis_error(err);
		return NULL;
	}
311

312
	while (!server && aliases[mapi].map != 0L) {
Barry Warsaw's avatar
Barry Warsaw committed
313 314 315
		yp_master (dom, aliases[mapi].map, &server);
		mapi++;
	}
316
        if (!server) {
Barry Warsaw's avatar
Barry Warsaw committed
317 318 319
            PyErr_SetString(NisError, "No NIS master found for any map");
            return NULL;
        }
320 321
	cl = clnt_create(server, YPPROG, YPVERS, "tcp");
	if (cl == NULL) {
Barry Warsaw's avatar
Barry Warsaw committed
322
		PyErr_SetString(NisError, clnt_spcreateerror(server));
323
		goto finally;
324 325
	}
	list = nisproc_maplist_2 (&dom, cl);
326
	clnt_destroy(cl);
327
	if (list == NULL)
328
		goto finally;
329
	if (list->stat != NIS_TRUE)
330 331
		goto finally;

332
	free(server);
333
	return list->maps;
334 335

  finally:
336
	free(server);
337
	return NULL;
338 339
}

Barry Warsaw's avatar
Barry Warsaw committed
340
static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
341
nis_maps (PyObject *self, PyObject *args)
342
{
343
	nismaplist *maps;
Barry Warsaw's avatar
Barry Warsaw committed
344
	PyObject *list;
345

346 347
        if (!PyArg_NoArgs(args))
		return NULL;
348 349
	if ((maps = nis_maplist ()) == NULL)
		return NULL;
Barry Warsaw's avatar
Barry Warsaw committed
350
	if ((list = PyList_New(0)) == NULL)
351
		return NULL;
352
	for (maps = maps; maps; maps = maps->next) {
353 354
		PyObject *str = PyString_FromString(maps->map);
		if (!str || PyList_Append(list, str) < 0)
Barry Warsaw's avatar
Barry Warsaw committed
355 356
		{
			Py_DECREF(list);
357 358 359
			list = NULL;
			break;
		}
360
		Py_DECREF(str);
361 362
	}
	/* XXX Shouldn't we free the list of maps now? */
363 364 365
	return list;
}

Barry Warsaw's avatar
Barry Warsaw committed
366
static PyMethodDef nis_methods[] = {
367 368 369 370 371 372 373
	{"match",	nis_match},
	{"cat",		nis_cat},
	{"maps",	nis_maps},
	{NULL,		NULL}		 /* Sentinel */
};

void
374
initnis (void)
375
{
Barry Warsaw's avatar
Barry Warsaw committed
376 377 378
	PyObject *m, *d;
	m = Py_InitModule("nis", nis_methods);
	d = PyModule_GetDict(m);
379 380 381
	NisError = PyErr_NewException("nis.error", NULL, NULL);
	if (NisError != NULL)
		PyDict_SetItemString(d, "error", NisError);
382
}