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 */ 23extern int yp_get_default_domain(char **); 24#endif 25 26PyDoc_STRVAR(get_default_domain__doc__, 27"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 47static PyObject *NisError; 48 49static PyObject * 50nis_error (int err) 51{ 52 PyErr_SetString(NisError, yperr_string(err)); 53 return NULL; 54} 55 56static 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 72static char * 73nis_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__) 93typedef int (*foreachfunc)(unsigned long, char *, int, char *, int, void *); 94#else 95typedef int (*foreachfunc)(int, char *, int, char *, int, char *); 96#endif 97 98struct ypcallback_data { 99 PyObject *dict; 100 int fix; 101 PyThreadState *state; 102}; 103 104static int 105nis_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 143static PyObject * 144nis_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 157static PyObject * 158nis_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 190static PyObject * 191nis_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 235typedef char *domainname; 236typedef char *mapname; 237 238enum 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}; 251typedef enum nisstat nisstat; 252 253struct nismaplist { 254 mapname map; 255 struct nismaplist *next; 256}; 257typedef struct nismaplist nismaplist; 258 259struct nisresp_maplist { 260 nisstat stat; 261 nismaplist *maps; 262}; 263typedef struct nisresp_maplist nisresp_maplist; 264 265static struct timeval TIMEOUT = { 25, 0 }; 266 267static 268bool_t 269nis_xdr_domainname(XDR *xdrs, domainname *objp) 270{ 271 if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) { 272 return (FALSE); 273 } 274 return (TRUE); 275} 276 277static 278bool_t 279nis_xdr_mapname(XDR *xdrs, mapname *objp) 280{ 281 if (!xdr_string(xdrs, objp, YPMAXMAP)) { 282 return (FALSE); 283 } 284 return (TRUE); 285} 286 287static 288bool_t 289nis_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 302static 303bool_t 304nis_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 313static 314bool_t 315nis_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 329static 330nisresp_maplist * 331nisproc_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 346static 347nismaplist * 348nis_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 383static PyObject * 384nis_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 418static 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 434PyDoc_STRVAR(nis__doc__, 435"This module contains functions for accessing NIS maps.\n"); 436 437void 438initnis (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} 449