1 /*********************************************************** 2 Written by: 3 Fred Gansevles <Fred.Gansevles (at) 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 } 449