Python-2.7.3/Modules/nismodule.c

No issues found

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