Speed-up isinstance() for one easy case.
[python.git] / Modules / nismodule.c
blob0811430cf03fe605077eabfd95f8c0833728b791
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 #ifdef __APPLE__
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;
103 static int
104 nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
105 int invallen, struct ypcallback_data *indata)
107 if (instatus == YP_TRUE) {
108 PyObject *key;
109 PyObject *val;
110 int err;
112 if (indata->fix) {
113 if (inkeylen > 0 && inkey[inkeylen-1] == '\0')
114 inkeylen--;
115 if (invallen > 0 && inval[invallen-1] == '\0')
116 invallen--;
118 key = PyString_FromStringAndSize(inkey, inkeylen);
119 val = PyString_FromStringAndSize(inval, invallen);
120 if (key == NULL || val == NULL) {
121 /* XXX error -- don't know how to handle */
122 PyErr_Clear();
123 Py_XDECREF(key);
124 Py_XDECREF(val);
125 return 1;
127 err = PyDict_SetItem(indata->dict, key, val);
128 Py_DECREF(key);
129 Py_DECREF(val);
130 if (err != 0) {
131 PyErr_Clear();
132 return 1;
134 return 0;
136 return 1;
139 static PyObject *
140 nis_get_default_domain (PyObject *self)
142 char *domain;
143 int err;
144 PyObject *res;
146 if ((err = yp_get_default_domain(&domain)) != 0)
147 return nis_error(err);
149 res = PyString_FromStringAndSize (domain, strlen(domain));
150 return res;
153 static PyObject *
154 nis_match (PyObject *self, PyObject *args, PyObject *kwdict)
156 char *match;
157 char *domain = NULL;
158 int keylen, len;
159 char *key, *map;
160 int err;
161 PyObject *res;
162 int fix;
163 static char *kwlist[] = {"key", "map", "domain", NULL};
165 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
166 "t#s|s:match", kwlist,
167 &key, &keylen, &map, &domain))
168 return NULL;
169 if (!domain && ((err = yp_get_default_domain(&domain)) != 0))
170 return nis_error(err);
171 map = nis_mapname (map, &fix);
172 if (fix)
173 keylen++;
174 Py_BEGIN_ALLOW_THREADS
175 err = yp_match (domain, map, key, keylen, &match, &len);
176 Py_END_ALLOW_THREADS
177 if (fix)
178 len--;
179 if (err != 0)
180 return nis_error(err);
181 res = PyString_FromStringAndSize (match, len);
182 free (match);
183 return res;
186 static PyObject *
187 nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
189 char *domain = NULL;
190 char *map;
191 struct ypall_callback cb;
192 struct ypcallback_data data;
193 PyObject *dict;
194 int err;
195 static char *kwlist[] = {"map", "domain", NULL};
197 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat",
198 kwlist, &map, &domain))
199 return NULL;
200 if (!domain && ((err = yp_get_default_domain(&domain)) != 0))
201 return nis_error(err);
202 dict = PyDict_New ();
203 if (dict == NULL)
204 return NULL;
205 cb.foreach = (foreachfunc)nis_foreach;
206 data.dict = dict;
207 map = nis_mapname (map, &data.fix);
208 cb.data = (char *)&data;
209 Py_BEGIN_ALLOW_THREADS
210 err = yp_all (domain, map, &cb);
211 Py_END_ALLOW_THREADS
212 if (err != 0) {
213 Py_DECREF(dict);
214 return nis_error(err);
216 return dict;
219 /* These should be u_long on Sun h/w but not on 64-bit h/w.
220 This is not portable to machines with 16-bit ints and no prototypes */
221 #ifndef YPPROC_MAPLIST
222 #define YPPROC_MAPLIST 11
223 #endif
224 #ifndef YPPROG
225 #define YPPROG 100004
226 #endif
227 #ifndef YPVERS
228 #define YPVERS 2
229 #endif
231 typedef char *domainname;
232 typedef char *mapname;
234 enum nisstat {
235 NIS_TRUE = 1,
236 NIS_NOMORE = 2,
237 NIS_FALSE = 0,
238 NIS_NOMAP = -1,
239 NIS_NODOM = -2,
240 NIS_NOKEY = -3,
241 NIS_BADOP = -4,
242 NIS_BADDB = -5,
243 NIS_YPERR = -6,
244 NIS_BADARGS = -7,
245 NIS_VERS = -8
247 typedef enum nisstat nisstat;
249 struct nismaplist {
250 mapname map;
251 struct nismaplist *next;
253 typedef struct nismaplist nismaplist;
255 struct nisresp_maplist {
256 nisstat stat;
257 nismaplist *maps;
259 typedef struct nisresp_maplist nisresp_maplist;
261 static struct timeval TIMEOUT = { 25, 0 };
263 static
264 bool_t
265 nis_xdr_domainname(XDR *xdrs, domainname *objp)
267 if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
268 return (FALSE);
270 return (TRUE);
273 static
274 bool_t
275 nis_xdr_mapname(XDR *xdrs, mapname *objp)
277 if (!xdr_string(xdrs, objp, YPMAXMAP)) {
278 return (FALSE);
280 return (TRUE);
283 static
284 bool_t
285 nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
287 if (!nis_xdr_mapname(xdrs, &objp->map)) {
288 return (FALSE);
290 if (!xdr_pointer(xdrs, (char **)&objp->next,
291 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
293 return (FALSE);
295 return (TRUE);
298 static
299 bool_t
300 nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
302 if (!xdr_enum(xdrs, (enum_t *)objp)) {
303 return (FALSE);
305 return (TRUE);
309 static
310 bool_t
311 nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
313 if (!nis_xdr_ypstat(xdrs, &objp->stat)) {
314 return (FALSE);
316 if (!xdr_pointer(xdrs, (char **)&objp->maps,
317 sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
319 return (FALSE);
321 return (TRUE);
325 static
326 nisresp_maplist *
327 nisproc_maplist_2(domainname *argp, CLIENT *clnt)
329 static nisresp_maplist res;
331 memset(&res, 0, sizeof(res));
332 if (clnt_call(clnt, YPPROC_MAPLIST,
333 (xdrproc_t)nis_xdr_domainname, (caddr_t)argp,
334 (xdrproc_t)nis_xdr_ypresp_maplist, (caddr_t)&res,
335 TIMEOUT) != RPC_SUCCESS)
337 return (NULL);
339 return (&res);
342 static
343 nismaplist *
344 nis_maplist (char *dom)
346 nisresp_maplist *list;
347 CLIENT *cl;
348 char *server = NULL;
349 int mapi = 0;
351 while (!server && aliases[mapi].map != 0L) {
352 yp_master (dom, aliases[mapi].map, &server);
353 mapi++;
355 if (!server) {
356 PyErr_SetString(NisError, "No NIS master found for any map");
357 return NULL;
359 cl = clnt_create(server, YPPROG, YPVERS, "tcp");
360 if (cl == NULL) {
361 PyErr_SetString(NisError, clnt_spcreateerror(server));
362 goto finally;
364 list = nisproc_maplist_2 (&dom, cl);
365 clnt_destroy(cl);
366 if (list == NULL)
367 goto finally;
368 if (list->stat != NIS_TRUE)
369 goto finally;
371 free(server);
372 return list->maps;
374 finally:
375 free(server);
376 return NULL;
379 static PyObject *
380 nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
382 char *domain = NULL;
383 nismaplist *maps;
384 PyObject *list;
385 int err;
386 static char *kwlist[] = {"domain", NULL};
388 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
389 "|s:maps", kwlist, &domain))
390 return NULL;
391 if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) {
392 nis_error(err);
393 return NULL;
396 if ((maps = nis_maplist (domain)) == NULL)
397 return NULL;
398 if ((list = PyList_New(0)) == NULL)
399 return NULL;
400 for (maps = maps; maps; maps = maps->next) {
401 PyObject *str = PyString_FromString(maps->map);
402 if (!str || PyList_Append(list, str) < 0)
404 Py_DECREF(list);
405 list = NULL;
406 break;
408 Py_DECREF(str);
410 /* XXX Shouldn't we free the list of maps now? */
411 return list;
414 static PyMethodDef nis_methods[] = {
415 {"match", (PyCFunction)nis_match,
416 METH_VARARGS | METH_KEYWORDS,
417 match__doc__},
418 {"cat", (PyCFunction)nis_cat,
419 METH_VARARGS | METH_KEYWORDS,
420 cat__doc__},
421 {"maps", (PyCFunction)nis_maps,
422 METH_VARARGS | METH_KEYWORDS,
423 maps__doc__},
424 {"get_default_domain", (PyCFunction)nis_get_default_domain,
425 METH_NOARGS,
426 get_default_domain__doc__},
427 {NULL, NULL} /* Sentinel */
430 PyDoc_STRVAR(nis__doc__,
431 "This module contains functions for accessing NIS maps.\n");
433 void
434 initnis (void)
436 PyObject *m, *d;
437 m = Py_InitModule3("nis", nis_methods, nis__doc__);
438 if (m == NULL)
439 return;
440 d = PyModule_GetDict(m);
441 NisError = PyErr_NewException("nis.error", NULL, NULL);
442 if (NisError != NULL)
443 PyDict_SetItemString(d, "error", NisError);