/Modules/nismodule.c

http://unladen-swallow.googlecode.com/ · C · 447 lines · 382 code · 50 blank · 15 comment · 75 complexity · 1b9df5ea7c5dfa06c1902687476f0df5 MD5 · raw file

  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. /* NIS module implementation */
  11. #include "Python.h"
  12. #include <sys/time.h>
  13. #include <sys/types.h>
  14. #include <rpc/rpc.h>
  15. #include <rpcsvc/yp_prot.h>
  16. #include <rpcsvc/ypclnt.h>
  17. #ifdef __sgi
  18. /* This is missing from rpcsvc/ypclnt.h */
  19. extern int yp_get_default_domain(char **);
  20. #endif
  21. PyDoc_STRVAR(get_default_domain__doc__,
  22. "get_default_domain() -> str\n\
  23. Corresponds to the C library yp_get_default_domain() call, returning\n\
  24. the default NIS domain.\n");
  25. PyDoc_STRVAR(match__doc__,
  26. "match(key, map, domain = defaultdomain)\n\
  27. Corresponds to the C library yp_match() call, returning the value of\n\
  28. key in the given map. Optionally domain can be specified but it\n\
  29. defaults to the system default domain.\n");
  30. PyDoc_STRVAR(cat__doc__,
  31. "cat(map, domain = defaultdomain)\n\
  32. Returns the entire map as a dictionary. Optionally domain can be\n\
  33. specified but it defaults to the system default domain.\n");
  34. PyDoc_STRVAR(maps__doc__,
  35. "maps(domain = defaultdomain)\n\
  36. Returns an array of all available NIS maps within a domain. If domain\n\
  37. is not specified it defaults to the system default domain.\n");
  38. static PyObject *NisError;
  39. static PyObject *
  40. nis_error (int err)
  41. {
  42. PyErr_SetString(NisError, yperr_string(err));
  43. return NULL;
  44. }
  45. static struct nis_map {
  46. char *alias;
  47. char *map;
  48. int fix;
  49. } aliases [] = {
  50. {"passwd", "passwd.byname", 0},
  51. {"group", "group.byname", 0},
  52. {"networks", "networks.byaddr", 0},
  53. {"hosts", "hosts.byname", 0},
  54. {"protocols", "protocols.bynumber", 0},
  55. {"services", "services.byname", 0},
  56. {"aliases", "mail.aliases", 1}, /* created with 'makedbm -a' */
  57. {"ethers", "ethers.byname", 0},
  58. {0L, 0L, 0}
  59. };
  60. static char *
  61. nis_mapname (char *map, int *pfix)
  62. {
  63. int i;
  64. *pfix = 0;
  65. for (i=0; aliases[i].alias != 0L; i++) {
  66. if (!strcmp (aliases[i].alias, map)) {
  67. *pfix = aliases[i].fix;
  68. return aliases[i].map;
  69. }
  70. if (!strcmp (aliases[i].map, map)) {
  71. *pfix = aliases[i].fix;
  72. return aliases[i].map;
  73. }
  74. }
  75. return map;
  76. }
  77. #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
  78. typedef int (*foreachfunc)(unsigned long, char *, int, char *, int, void *);
  79. #else
  80. typedef int (*foreachfunc)(int, char *, int, char *, int, char *);
  81. #endif
  82. struct ypcallback_data {
  83. PyObject *dict;
  84. int fix;
  85. PyThreadState *state;
  86. };
  87. static int
  88. nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
  89. int invallen, struct ypcallback_data *indata)
  90. {
  91. if (instatus == YP_TRUE) {
  92. PyObject *key;
  93. PyObject *val;
  94. int err;
  95. PyEval_RestoreThread(indata->state);
  96. if (indata->fix) {
  97. if (inkeylen > 0 && inkey[inkeylen-1] == '\0')
  98. inkeylen--;
  99. if (invallen > 0 && inval[invallen-1] == '\0')
  100. invallen--;
  101. }
  102. key = PyString_FromStringAndSize(inkey, inkeylen);
  103. val = PyString_FromStringAndSize(inval, invallen);
  104. if (key == NULL || val == NULL) {
  105. /* XXX error -- don't know how to handle */
  106. PyErr_Clear();
  107. Py_XDECREF(key);
  108. Py_XDECREF(val);
  109. return 1;
  110. }
  111. err = PyDict_SetItem(indata->dict, key, val);
  112. Py_DECREF(key);
  113. Py_DECREF(val);
  114. if (err != 0)
  115. PyErr_Clear();
  116. indata->state = PyEval_SaveThread();
  117. if (err != 0)
  118. return 1;
  119. return 0;
  120. }
  121. return 1;
  122. }
  123. static PyObject *
  124. nis_get_default_domain (PyObject *self)
  125. {
  126. char *domain;
  127. int err;
  128. PyObject *res;
  129. if ((err = yp_get_default_domain(&domain)) != 0)
  130. return nis_error(err);
  131. res = PyString_FromStringAndSize (domain, strlen(domain));
  132. return res;
  133. }
  134. static PyObject *
  135. nis_match (PyObject *self, PyObject *args, PyObject *kwdict)
  136. {
  137. char *match;
  138. char *domain = NULL;
  139. int keylen, len;
  140. char *key, *map;
  141. int err;
  142. PyObject *res;
  143. int fix;
  144. static char *kwlist[] = {"key", "map", "domain", NULL};
  145. if (!PyArg_ParseTupleAndKeywords(args, kwdict,
  146. "t#s|s:match", kwlist,
  147. &key, &keylen, &map, &domain))
  148. return NULL;
  149. if (!domain && ((err = yp_get_default_domain(&domain)) != 0))
  150. return nis_error(err);
  151. map = nis_mapname (map, &fix);
  152. if (fix)
  153. keylen++;
  154. Py_BEGIN_ALLOW_THREADS
  155. err = yp_match (domain, map, key, keylen, &match, &len);
  156. Py_END_ALLOW_THREADS
  157. if (fix)
  158. len--;
  159. if (err != 0)
  160. return nis_error(err);
  161. res = PyString_FromStringAndSize (match, len);
  162. free (match);
  163. return res;
  164. }
  165. static PyObject *
  166. nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
  167. {
  168. char *domain = NULL;
  169. char *map;
  170. struct ypall_callback cb;
  171. struct ypcallback_data data;
  172. PyObject *dict;
  173. int err;
  174. static char *kwlist[] = {"map", "domain", NULL};
  175. if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat",
  176. kwlist, &map, &domain))
  177. return NULL;
  178. if (!domain && ((err = yp_get_default_domain(&domain)) != 0))
  179. return nis_error(err);
  180. dict = PyDict_New ();
  181. if (dict == NULL)
  182. return NULL;
  183. cb.foreach = (foreachfunc)nis_foreach;
  184. data.dict = dict;
  185. map = nis_mapname (map, &data.fix);
  186. cb.data = (char *)&data;
  187. data.state = PyEval_SaveThread();
  188. err = yp_all (domain, map, &cb);
  189. PyEval_RestoreThread(data.state);
  190. if (err != 0) {
  191. Py_DECREF(dict);
  192. return nis_error(err);
  193. }
  194. return dict;
  195. }
  196. /* These should be u_long on Sun h/w but not on 64-bit h/w.
  197. This is not portable to machines with 16-bit ints and no prototypes */
  198. #ifndef YPPROC_MAPLIST
  199. #define YPPROC_MAPLIST 11
  200. #endif
  201. #ifndef YPPROG
  202. #define YPPROG 100004
  203. #endif
  204. #ifndef YPVERS
  205. #define YPVERS 2
  206. #endif
  207. typedef char *domainname;
  208. typedef char *mapname;
  209. enum nisstat {
  210. NIS_TRUE = 1,
  211. NIS_NOMORE = 2,
  212. NIS_FALSE = 0,
  213. NIS_NOMAP = -1,
  214. NIS_NODOM = -2,
  215. NIS_NOKEY = -3,
  216. NIS_BADOP = -4,
  217. NIS_BADDB = -5,
  218. NIS_YPERR = -6,
  219. NIS_BADARGS = -7,
  220. NIS_VERS = -8
  221. };
  222. typedef enum nisstat nisstat;
  223. struct nismaplist {
  224. mapname map;
  225. struct nismaplist *next;
  226. };
  227. typedef struct nismaplist nismaplist;
  228. struct nisresp_maplist {
  229. nisstat stat;
  230. nismaplist *maps;
  231. };
  232. typedef struct nisresp_maplist nisresp_maplist;
  233. static struct timeval TIMEOUT = { 25, 0 };
  234. static
  235. bool_t
  236. nis_xdr_domainname(XDR *xdrs, domainname *objp)
  237. {
  238. if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
  239. return (FALSE);
  240. }
  241. return (TRUE);
  242. }
  243. static
  244. bool_t
  245. nis_xdr_mapname(XDR *xdrs, mapname *objp)
  246. {
  247. if (!xdr_string(xdrs, objp, YPMAXMAP)) {
  248. return (FALSE);
  249. }
  250. return (TRUE);
  251. }
  252. static
  253. bool_t
  254. nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
  255. {
  256. if (!nis_xdr_mapname(xdrs, &objp->map)) {
  257. return (FALSE);
  258. }
  259. if (!xdr_pointer(xdrs, (char **)&objp->next,
  260. sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
  261. {
  262. return (FALSE);
  263. }
  264. return (TRUE);
  265. }
  266. static
  267. bool_t
  268. nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
  269. {
  270. if (!xdr_enum(xdrs, (enum_t *)objp)) {
  271. return (FALSE);
  272. }
  273. return (TRUE);
  274. }
  275. static
  276. bool_t
  277. nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
  278. {
  279. if (!nis_xdr_ypstat(xdrs, &objp->stat)) {
  280. return (FALSE);
  281. }
  282. if (!xdr_pointer(xdrs, (char **)&objp->maps,
  283. sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
  284. {
  285. return (FALSE);
  286. }
  287. return (TRUE);
  288. }
  289. static
  290. nisresp_maplist *
  291. nisproc_maplist_2(domainname *argp, CLIENT *clnt)
  292. {
  293. static nisresp_maplist res;
  294. memset(&res, 0, sizeof(res));
  295. if (clnt_call(clnt, YPPROC_MAPLIST,
  296. (xdrproc_t)nis_xdr_domainname, (caddr_t)argp,
  297. (xdrproc_t)nis_xdr_ypresp_maplist, (caddr_t)&res,
  298. TIMEOUT) != RPC_SUCCESS)
  299. {
  300. return (NULL);
  301. }
  302. return (&res);
  303. }
  304. static
  305. nismaplist *
  306. nis_maplist (char *dom)
  307. {
  308. nisresp_maplist *list;
  309. CLIENT *cl;
  310. char *server = NULL;
  311. int mapi = 0;
  312. while (!server && aliases[mapi].map != 0L) {
  313. yp_master (dom, aliases[mapi].map, &server);
  314. mapi++;
  315. }
  316. if (!server) {
  317. PyErr_SetString(NisError, "No NIS master found for any map");
  318. return NULL;
  319. }
  320. cl = clnt_create(server, YPPROG, YPVERS, "tcp");
  321. if (cl == NULL) {
  322. PyErr_SetString(NisError, clnt_spcreateerror(server));
  323. goto finally;
  324. }
  325. list = nisproc_maplist_2 (&dom, cl);
  326. clnt_destroy(cl);
  327. if (list == NULL)
  328. goto finally;
  329. if (list->stat != NIS_TRUE)
  330. goto finally;
  331. free(server);
  332. return list->maps;
  333. finally:
  334. free(server);
  335. return NULL;
  336. }
  337. static PyObject *
  338. nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
  339. {
  340. char *domain = NULL;
  341. nismaplist *maps;
  342. PyObject *list;
  343. int err;
  344. static char *kwlist[] = {"domain", NULL};
  345. if (!PyArg_ParseTupleAndKeywords(args, kwdict,
  346. "|s:maps", kwlist, &domain))
  347. return NULL;
  348. if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) {
  349. nis_error(err);
  350. return NULL;
  351. }
  352. if ((maps = nis_maplist (domain)) == NULL)
  353. return NULL;
  354. if ((list = PyList_New(0)) == NULL)
  355. return NULL;
  356. for (maps = maps; maps; maps = maps->next) {
  357. PyObject *str = PyString_FromString(maps->map);
  358. if (!str || PyList_Append(list, str) < 0)
  359. {
  360. Py_DECREF(list);
  361. list = NULL;
  362. break;
  363. }
  364. Py_DECREF(str);
  365. }
  366. /* XXX Shouldn't we free the list of maps now? */
  367. return list;
  368. }
  369. static PyMethodDef nis_methods[] = {
  370. {"match", (PyCFunction)nis_match,
  371. METH_VARARGS | METH_KEYWORDS,
  372. match__doc__},
  373. {"cat", (PyCFunction)nis_cat,
  374. METH_VARARGS | METH_KEYWORDS,
  375. cat__doc__},
  376. {"maps", (PyCFunction)nis_maps,
  377. METH_VARARGS | METH_KEYWORDS,
  378. maps__doc__},
  379. {"get_default_domain", (PyCFunction)nis_get_default_domain,
  380. METH_NOARGS,
  381. get_default_domain__doc__},
  382. {NULL, NULL} /* Sentinel */
  383. };
  384. PyDoc_STRVAR(nis__doc__,
  385. "This module contains functions for accessing NIS maps.\n");
  386. void
  387. initnis (void)
  388. {
  389. PyObject *m, *d;
  390. m = Py_InitModule3("nis", nis_methods, nis__doc__);
  391. if (m == NULL)
  392. return;
  393. d = PyModule_GetDict(m);
  394. NisError = PyErr_NewException("nis.error", NULL, NULL);
  395. if (NisError != NULL)
  396. PyDict_SetItemString(d, "error", NisError);
  397. }