blob: d75af5d589cd82966f2c0baa1eaccd935085237e [file] [log] [blame]
Guido van Rossum9de7a011992-08-12 14:57:12 +00001/***********************************************************
2 Written by:
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00003 Fred Gansevles <Fred.Gansevles@cs.utwente.nl>
4 B&O group,
5 Faculteit der Informatica,
6 Universiteit Twente,
7 Enschede,
8 the Netherlands.
Guido van Rossum9de7a011992-08-12 14:57:12 +00009******************************************************************/
10
11/* NIS module implementation */
12
Barry Warsawadbf4e61996-12-11 00:15:58 +000013#include "Python.h"
Guido van Rossum9de7a011992-08-12 14:57:12 +000014
Guido van Rossum9de7a011992-08-12 14:57:12 +000015#include <sys/time.h>
16#include <sys/types.h>
17#include <rpc/rpc.h>
18#include <rpcsvc/yp_prot.h>
Guido van Rossum8a170cb1996-08-08 19:11:41 +000019#include <rpcsvc/ypclnt.h>
Guido van Rossum9de7a011992-08-12 14:57:12 +000020
Guido van Rossum259552d1996-12-09 18:46:28 +000021#ifdef __sgi
22/* This is missing from rpcsvc/ypclnt.h */
Thomas Woutersbd4bc4e2000-07-22 23:57:55 +000023extern int yp_get_default_domain(char **);
Guido van Rossum259552d1996-12-09 18:46:28 +000024#endif
25
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000026PyDoc_STRVAR(get_default_domain__doc__,
Martin v. Löwis57a34e82006-02-04 19:12:37 +000027"get_default_domain() -> str\n\
28Corresponds to the C library yp_get_default_domain() call, returning\n\
29the default NIS domain.\n");
30
31PyDoc_STRVAR(match__doc__,
32"match(key, map, domain = defaultdomain)\n\
33Corresponds to the C library yp_match() call, returning the value of\n\
34key in the given map. Optionally domain can be specified but it\n\
35defaults to the system default domain.\n");
36
37PyDoc_STRVAR(cat__doc__,
38"cat(map, domain = defaultdomain)\n\
39Returns the entire map as a dictionary. Optionally domain can be\n\
40specified but it defaults to the system default domain.\n");
41
42PyDoc_STRVAR(maps__doc__,
43"maps(domain = defaultdomain)\n\
44Returns an array of all available NIS maps within a domain. If domain\n\
45is not specified it defaults to the system default domain.\n");
46
Barry Warsawadbf4e61996-12-11 00:15:58 +000047static PyObject *NisError;
Guido van Rossum3562d521992-08-12 15:26:16 +000048
Barry Warsawadbf4e61996-12-11 00:15:58 +000049static PyObject *
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +000050nis_error (int err)
Guido van Rossum3562d521992-08-12 15:26:16 +000051{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000052 PyErr_SetString(NisError, yperr_string(err));
53 return NULL;
Guido van Rossum3562d521992-08-12 15:26:16 +000054}
55
Guido van Rossum9de7a011992-08-12 14:57:12 +000056static struct nis_map {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000057 char *alias;
58 char *map;
59 int fix;
Guido van Rossum9de7a011992-08-12 14:57:12 +000060} aliases [] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000061 {"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}
Guido van Rossum9de7a011992-08-12 14:57:12 +000070};
71
72static char *
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +000073nis_mapname (char *map, int *pfix)
Guido van Rossum9de7a011992-08-12 14:57:12 +000074{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000075 int i;
Guido van Rossum9de7a011992-08-12 14:57:12 +000076
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000077 *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 }
Guido van Rossum61b705a2000-02-29 15:52:40 +000088
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000089 return map;
Guido van Rossum9de7a011992-08-12 14:57:12 +000090}
91
Amaury Forgeot d'Arc5f587b42009-07-07 06:53:22 +000092#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
Brett Cannonf6067ec2004-07-10 00:57:37 +000093typedef int (*foreachfunc)(unsigned long, char *, int, char *, int, void *);
94#else
Tim Petersdbd9ba62000-07-09 03:09:57 +000095typedef int (*foreachfunc)(int, char *, int, char *, int, char *);
Brett Cannonf6067ec2004-07-10 00:57:37 +000096#endif
Guido van Rossumb6775db1994-08-01 11:34:53 +000097
Guido van Rossum61b705a2000-02-29 15:52:40 +000098struct ypcallback_data {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000099 PyObject *dict;
100 int fix;
101 PyThreadState *state;
Guido van Rossum61b705a2000-02-29 15:52:40 +0000102};
103
Guido van Rossum9de7a011992-08-12 14:57:12 +0000104static int
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +0000105nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
106 int invallen, struct ypcallback_data *indata)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000107{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000108 if (instatus == YP_TRUE) {
109 PyObject *key;
110 PyObject *val;
111 int err;
Guido van Rossum61b705a2000-02-29 15:52:40 +0000112
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000113 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 = PyUnicode_FromStringAndSize(inkey, inkeylen);
121 val = PyUnicode_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);
Martin v. Löwisa5154ad2010-08-19 09:03:03 +0000127 indata->state = PyEval_SaveThread();
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000128 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;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000141}
142
Barry Warsawadbf4e61996-12-11 00:15:58 +0000143static PyObject *
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000144nis_get_default_domain (PyObject *self)
145{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000146 char *domain;
147 int err;
148 PyObject *res;
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000149
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000150 if ((err = yp_get_default_domain(&domain)) != 0)
151 return nis_error(err);
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000152
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000153 res = PyUnicode_FromStringAndSize (domain, strlen(domain));
154 return res;
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000155}
156
157static PyObject *
158nis_match (PyObject *self, PyObject *args, PyObject *kwdict)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000159{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000160 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};
Guido van Rossum9de7a011992-08-12 14:57:12 +0000168
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000169 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
170 "s#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 = PyUnicode_FromStringAndSize (match, len);
186 free (match);
187 return res;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000188}
189
Barry Warsawadbf4e61996-12-11 00:15:58 +0000190static PyObject *
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000191nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000192{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000193 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};
Guido van Rossum9de7a011992-08-12 14:57:12 +0000200
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000201 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;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000221}
222
Guido van Rossumb6775db1994-08-01 11:34:53 +0000223/* 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
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000226#define YPPROC_MAPLIST 11
Guido van Rossumb6775db1994-08-01 11:34:53 +0000227#endif
228#ifndef YPPROG
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000229#define YPPROG 100004
Guido van Rossumb6775db1994-08-01 11:34:53 +0000230#endif
231#ifndef YPVERS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000232#define YPVERS 2
Guido van Rossumb6775db1994-08-01 11:34:53 +0000233#endif
Guido van Rossum9de7a011992-08-12 14:57:12 +0000234
235typedef char *domainname;
236typedef char *mapname;
237
238enum nisstat {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000239 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
Guido van Rossum9de7a011992-08-12 14:57:12 +0000250};
251typedef enum nisstat nisstat;
252
253struct nismaplist {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000254 mapname map;
255 struct nismaplist *next;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000256};
257typedef struct nismaplist nismaplist;
258
259struct nisresp_maplist {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000260 nisstat stat;
261 nismaplist *maps;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000262};
263typedef struct nisresp_maplist nisresp_maplist;
264
265static struct timeval TIMEOUT = { 25, 0 };
266
267static
268bool_t
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +0000269nis_xdr_domainname(XDR *xdrs, domainname *objp)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000270{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000271 if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
272 return (FALSE);
273 }
274 return (TRUE);
Guido van Rossum9de7a011992-08-12 14:57:12 +0000275}
276
277static
278bool_t
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +0000279nis_xdr_mapname(XDR *xdrs, mapname *objp)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000280{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000281 if (!xdr_string(xdrs, objp, YPMAXMAP)) {
282 return (FALSE);
283 }
284 return (TRUE);
Guido van Rossum9de7a011992-08-12 14:57:12 +0000285}
286
287static
288bool_t
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +0000289nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000290{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000291 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);
Guido van Rossum9de7a011992-08-12 14:57:12 +0000300}
301
302static
303bool_t
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +0000304nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000305{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000306 if (!xdr_enum(xdrs, (enum_t *)objp)) {
307 return (FALSE);
308 }
309 return (TRUE);
Guido van Rossum9de7a011992-08-12 14:57:12 +0000310}
311
312
313static
314bool_t
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +0000315nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000316{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000317 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);
Guido van Rossum9de7a011992-08-12 14:57:12 +0000326}
327
328
329static
330nisresp_maplist *
Peter Schneider-Kamp39e0e5a2000-07-10 13:12:27 +0000331nisproc_maplist_2(domainname *argp, CLIENT *clnt)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000332{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000333 static nisresp_maplist res;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000334
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000335 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);
Guido van Rossum9de7a011992-08-12 14:57:12 +0000344}
345
346static
347nismaplist *
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000348nis_maplist (char *dom)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000349{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000350 nisresp_maplist *list;
351 CLIENT *cl;
352 char *server = NULL;
353 int mapi = 0;
Barry Warsaw3696c521996-12-11 00:29:14 +0000354
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000355 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;
Barry Warsaw4bc9d391997-01-09 22:22:05 +0000374
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000375 free(server);
376 return list->maps;
Barry Warsaw4bc9d391997-01-09 22:22:05 +0000377
378 finally:
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000379 free(server);
380 return NULL;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000381}
382
Barry Warsawadbf4e61996-12-11 00:15:58 +0000383static PyObject *
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000384nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000385{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000386 char *domain = NULL;
387 nismaplist *maps;
388 PyObject *list;
389 int err;
390 static char *kwlist[] = {"domain", NULL};
Guido van Rossum9de7a011992-08-12 14:57:12 +0000391
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000392 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 }
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000399
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000400 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 = PyUnicode_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;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000416}
417
Barry Warsawadbf4e61996-12-11 00:15:58 +0000418static PyMethodDef nis_methods[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000419 {"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 */
Guido van Rossum9de7a011992-08-12 14:57:12 +0000432};
433
Martin v. Löwis57a34e82006-02-04 19:12:37 +0000434PyDoc_STRVAR(nis__doc__,
435"This module contains functions for accessing NIS maps.\n");
436
Martin v. Löwis1a214512008-06-11 05:26:20 +0000437static struct PyModuleDef nismodule = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000438 PyModuleDef_HEAD_INIT,
439 "nis",
440 nis__doc__,
441 -1,
442 nis_methods,
443 NULL,
444 NULL,
445 NULL,
446 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000447};
448
449PyObject*
450PyInit_nis (void)
Guido van Rossum9de7a011992-08-12 14:57:12 +0000451{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000452 PyObject *m, *d;
453 m = PyModule_Create(&nismodule);
454 if (m == NULL)
455 return NULL;
456 d = PyModule_GetDict(m);
457 NisError = PyErr_NewException("nis.error", NULL, NULL);
458 if (NisError != NULL)
459 PyDict_SetItemString(d, "error", NisError);
460 return m;
Guido van Rossum9de7a011992-08-12 14:57:12 +0000461}