Fix issue number in comment.
[python.git] / Modules / nismodule.c
blob9fbab5a11f689e2194f88fabba1a63838f16ee47
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 ******************************************************************/
11 /* NIS module implementation */
13 #include "Python.h"
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>
21 #ifdef __sgi
22 /* This is missing from rpcsvc/ypclnt.h */
23 extern int yp_get_default_domain(char **);
24 #endif
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");
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");
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");
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");
47 static PyObject *NisError;
49 static PyObject *
50 nis_error (int err)
52 PyErr_SetString(NisError, yperr_string(err));
53 return NULL;
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}
72 static char *
73 nis_mapname (char *map, int *pfix)
75 int i;
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;
83 if (!strcmp (aliases[i].map, map)) {
84 *pfix = aliases[i].fix;
85 return aliases[i].map;
89 return map;
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
98 struct ypcallback_data {
99 PyObject *dict;
100 int fix;
101 PyThreadState *state;
104 static int
105 nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
106 int invallen, struct ypcallback_data *indata)
108 if (instatus == YP_TRUE) {
109 PyObject *key;
110 PyObject *val;
111 int err;
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--;
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;
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;
139 return 1;
142 static PyObject *
143 nis_get_default_domain (PyObject *self)
145 char *domain;
146 int err;
147 PyObject *res;
149 if ((err = yp_get_default_domain(&domain)) != 0)
150 return nis_error(err);
152 res = PyString_FromStringAndSize (domain, strlen(domain));
153 return res;
156 static PyObject *
157 nis_match (PyObject *self, PyObject *args, PyObject *kwdict)
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};
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;
189 static PyObject *
190 nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
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};
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);
219 return dict;
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
234 typedef char *domainname;
235 typedef char *mapname;
237 enum 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
250 typedef enum nisstat nisstat;
252 struct nismaplist {
253 mapname map;
254 struct nismaplist *next;
256 typedef struct nismaplist nismaplist;
258 struct nisresp_maplist {
259 nisstat stat;
260 nismaplist *maps;
262 typedef struct nisresp_maplist nisresp_maplist;
264 static struct timeval TIMEOUT = { 25, 0 };
266 static
267 bool_t
268 nis_xdr_domainname(XDR *xdrs, domainname *objp)
270 if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
271 return (FALSE);
273 return (TRUE);
276 static
277 bool_t
278 nis_xdr_mapname(XDR *xdrs, mapname *objp)
280 if (!xdr_string(xdrs, objp, YPMAXMAP)) {
281 return (FALSE);
283 return (TRUE);
286 static
287 bool_t
288 nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
290 if (!nis_xdr_mapname(xdrs, &objp->map)) {
291 return (FALSE);
293 if (!xdr_pointer(xdrs, (char **)&objp->next,
294 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
296 return (FALSE);
298 return (TRUE);
301 static
302 bool_t
303 nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
305 if (!xdr_enum(xdrs, (enum_t *)objp)) {
306 return (FALSE);
308 return (TRUE);
312 static
313 bool_t
314 nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
316 if (!nis_xdr_ypstat(xdrs, &objp->stat)) {
317 return (FALSE);
319 if (!xdr_pointer(xdrs, (char **)&objp->maps,
320 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
322 return (FALSE);
324 return (TRUE);
328 static
329 nisresp_maplist *
330 nisproc_maplist_2(domainname *argp, CLIENT *clnt)
332 static nisresp_maplist res;
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)
340 return (NULL);
342 return (&res);
345 static
346 nismaplist *
347 nis_maplist (char *dom)
349 nisresp_maplist *list;
350 CLIENT *cl;
351 char *server = NULL;
352 int mapi = 0;
354 while (!server && aliases[mapi].map != 0L) {
355 yp_master (dom, aliases[mapi].map, &server);
356 mapi++;
358 if (!server) {
359 PyErr_SetString(NisError, "No NIS master found for any map");
360 return NULL;
362 cl = clnt_create(server, YPPROG, YPVERS, "tcp");
363 if (cl == NULL) {
364 PyErr_SetString(NisError, clnt_spcreateerror(server));
365 goto finally;
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;
374 free(server);
375 return list->maps;
377 finally:
378 free(server);
379 return NULL;
382 static PyObject *
383 nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
385 char *domain = NULL;
386 nismaplist *maps;
387 PyObject *list;
388 int err;
389 static char *kwlist[] = {"domain", NULL};
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;
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)
407 Py_DECREF(list);
408 list = NULL;
409 break;
411 Py_DECREF(str);
413 /* XXX Shouldn't we free the list of maps now? */
414 return list;
417 static 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 */
433 PyDoc_STRVAR(nis__doc__,
434 "This module contains functions for accessing NIS maps.\n");
436 void
437 initnis (void)
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);