mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00

Two interesting problems in nis_maplist(). First, it is possible that clnt_create() will return NULL. This was being caught, but no Python error was being set. I use clnt_spcreateerror() to generate the value of the exception. But why would clnt_create() fail? It's because no server was being found. And why was this? It was because nis_maplist() tried only to get the NIS master for the first map in the aliases list, which is passwd.byname, and guess what? That's the one NIS map CNRI does *not* export! So the yp_master() call was failing to return a valid server. I now cycle through all the map aliases until I find a valid master. If not, a different exception is set. I'm not sure this is the completely correct way to do all this, but short of rewriting the entire nismodule.c (to expose the proper API to Python), it should do the trick.
361 lines
6.7 KiB
C
361 lines
6.7 KiB
C
/***********************************************************
|
|
Written by:
|
|
Fred Gansevles <Fred.Gansevles@cs.utwente.nl>
|
|
Vakgroep Spa,
|
|
Faculteit der Informatica,
|
|
Universiteit Twente,
|
|
Enschede,
|
|
the Netherlands.
|
|
******************************************************************/
|
|
|
|
/* NIS module implementation */
|
|
|
|
#include "Python.h"
|
|
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <rpc/rpc.h>
|
|
#include <rpcsvc/yp_prot.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
|
|
#ifdef __sgi
|
|
/* This is missing from rpcsvc/ypclnt.h */
|
|
extern int yp_get_default_domain();
|
|
#endif
|
|
|
|
static PyObject *NisError;
|
|
|
|
static PyObject *
|
|
nis_error (err)
|
|
int err;
|
|
{
|
|
PyErr_SetString(NisError, yperr_string(err));
|
|
return NULL;
|
|
}
|
|
|
|
static struct nis_map {
|
|
char *alias;
|
|
char *map;
|
|
} aliases [] = {
|
|
{"passwd", "passwd.byname"},
|
|
{"group", "group.byname"},
|
|
{"networks", "networks.byaddr"},
|
|
{"hosts", "hosts.byname"},
|
|
{"protocols", "protocols.bynumber"},
|
|
{"services", "services.byname"},
|
|
{"aliases", "mail.aliases"},
|
|
{"ethers", "ethers.byname"},
|
|
{0L, 0L}
|
|
};
|
|
|
|
static char *
|
|
nis_mapname (map)
|
|
char *map;
|
|
{
|
|
int i;
|
|
|
|
for (i=0; aliases[i].alias != 0L; i++)
|
|
if (!strcmp (aliases[i].alias, map))
|
|
map = aliases[i].map;
|
|
return map;
|
|
}
|
|
|
|
typedef int (*foreachfunc) Py_PROTO((int, char *, int, char *, int, char *));
|
|
|
|
static int
|
|
nis_foreach (instatus, inkey, inkeylen, inval, invallen, indata)
|
|
int instatus;
|
|
char *inkey;
|
|
int inkeylen;
|
|
char *inval;
|
|
int invallen;
|
|
PyObject *indata;
|
|
{
|
|
if (instatus == YP_TRUE) {
|
|
PyObject *key = PyString_FromStringAndSize(inkey, inkeylen);
|
|
PyObject *val = PyString_FromStringAndSize(inval, invallen);
|
|
int err;
|
|
if (key == NULL || val == NULL) {
|
|
/* XXX error -- don't know how to handle */
|
|
PyErr_Clear();
|
|
Py_XDECREF(key);
|
|
Py_XDECREF(val);
|
|
return 1;
|
|
}
|
|
err = PyDict_SetItem(indata, key, val);
|
|
Py_DECREF(key);
|
|
Py_DECREF(val);
|
|
if (err != 0) {
|
|
PyErr_Clear();
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static PyObject *
|
|
nis_match (self, args)
|
|
PyObject *self;
|
|
PyObject *args;
|
|
{
|
|
char *match;
|
|
char *domain;
|
|
int keylen, len;
|
|
char *key, *map;
|
|
int err;
|
|
PyObject *res;
|
|
|
|
if (!PyArg_Parse(args, "(s#s)", &key, &keylen, &map))
|
|
return NULL;
|
|
if ((err = yp_get_default_domain(&domain)) != 0)
|
|
return nis_error(err);
|
|
Py_BEGIN_ALLOW_THREADS
|
|
map = nis_mapname (map);
|
|
err = yp_match (domain, map, key, keylen, &match, &len);
|
|
Py_END_ALLOW_THREADS
|
|
if (err != 0)
|
|
return nis_error(err);
|
|
res = PyString_FromStringAndSize (match, len);
|
|
free (match);
|
|
return res;
|
|
}
|
|
|
|
static PyObject *
|
|
nis_cat (self, args)
|
|
PyObject *self;
|
|
PyObject *args;
|
|
{
|
|
char *domain;
|
|
char *map;
|
|
struct ypall_callback cb;
|
|
PyObject *cat;
|
|
int err;
|
|
|
|
if (!PyArg_Parse(args, "s", &map))
|
|
return NULL;
|
|
if ((err = yp_get_default_domain(&domain)) != 0)
|
|
return nis_error(err);
|
|
cat = PyDict_New ();
|
|
if (cat == NULL)
|
|
return NULL;
|
|
cb.foreach = (foreachfunc)nis_foreach;
|
|
cb.data = (char *)cat;
|
|
Py_BEGIN_ALLOW_THREADS
|
|
map = nis_mapname (map);
|
|
err = yp_all (domain, map, &cb);
|
|
Py_END_ALLOW_THREADS
|
|
if (err != 0) {
|
|
Py_DECREF(cat);
|
|
return nis_error(err);
|
|
}
|
|
return cat;
|
|
}
|
|
|
|
/* These should be u_long on Sun h/w but not on 64-bit h/w.
|
|
This is not portable to machines with 16-bit ints and no prototypes */
|
|
#ifndef YPPROC_MAPLIST
|
|
#define YPPROC_MAPLIST 11
|
|
#endif
|
|
#ifndef YPPROG
|
|
#define YPPROG 100004
|
|
#endif
|
|
#ifndef YPVERS
|
|
#define YPVERS 2
|
|
#endif
|
|
|
|
typedef char *domainname;
|
|
typedef char *mapname;
|
|
|
|
enum nisstat {
|
|
NIS_TRUE = 1,
|
|
NIS_NOMORE = 2,
|
|
NIS_FALSE = 0,
|
|
NIS_NOMAP = -1,
|
|
NIS_NODOM = -2,
|
|
NIS_NOKEY = -3,
|
|
NIS_BADOP = -4,
|
|
NIS_BADDB = -5,
|
|
NIS_YPERR = -6,
|
|
NIS_BADARGS = -7,
|
|
NIS_VERS = -8
|
|
};
|
|
typedef enum nisstat nisstat;
|
|
|
|
struct nismaplist {
|
|
mapname map;
|
|
struct nismaplist *next;
|
|
};
|
|
typedef struct nismaplist nismaplist;
|
|
|
|
struct nisresp_maplist {
|
|
nisstat stat;
|
|
nismaplist *maps;
|
|
};
|
|
typedef struct nisresp_maplist nisresp_maplist;
|
|
|
|
static struct timeval TIMEOUT = { 25, 0 };
|
|
|
|
static
|
|
bool_t
|
|
nis_xdr_domainname(xdrs, objp)
|
|
XDR *xdrs;
|
|
domainname *objp;
|
|
{
|
|
if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
static
|
|
bool_t
|
|
nis_xdr_mapname(xdrs, objp)
|
|
XDR *xdrs;
|
|
mapname *objp;
|
|
{
|
|
if (!xdr_string(xdrs, objp, YPMAXMAP)) {
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
static
|
|
bool_t
|
|
nis_xdr_ypmaplist(xdrs, objp)
|
|
XDR *xdrs;
|
|
nismaplist *objp;
|
|
{
|
|
if (!nis_xdr_mapname(xdrs, &objp->map)) {
|
|
return (FALSE);
|
|
}
|
|
if (!xdr_pointer(xdrs, (char **)&objp->next,
|
|
sizeof(nismaplist), nis_xdr_ypmaplist))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
static
|
|
bool_t
|
|
nis_xdr_ypstat(xdrs, objp)
|
|
XDR *xdrs;
|
|
nisstat *objp;
|
|
{
|
|
if (!xdr_enum(xdrs, (enum_t *)objp)) {
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
static
|
|
bool_t
|
|
nis_xdr_ypresp_maplist(xdrs, objp)
|
|
XDR *xdrs;
|
|
nisresp_maplist *objp;
|
|
{
|
|
if (!nis_xdr_ypstat(xdrs, &objp->stat)) {
|
|
return (FALSE);
|
|
}
|
|
if (!xdr_pointer(xdrs, (char **)&objp->maps,
|
|
sizeof(nismaplist), nis_xdr_ypmaplist))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
static
|
|
nisresp_maplist *
|
|
nisproc_maplist_2(argp, clnt)
|
|
domainname *argp;
|
|
CLIENT *clnt;
|
|
{
|
|
static nisresp_maplist res;
|
|
|
|
memset(&res, 0, sizeof(res));
|
|
if (clnt_call(clnt, YPPROC_MAPLIST, nis_xdr_domainname, (caddr_t)argp,
|
|
nis_xdr_ypresp_maplist, (caddr_t)&res, TIMEOUT)
|
|
!= RPC_SUCCESS) {
|
|
return (NULL);
|
|
}
|
|
return (&res);
|
|
}
|
|
|
|
static
|
|
nismaplist *
|
|
nis_maplist ()
|
|
{
|
|
nisresp_maplist *list;
|
|
char *dom;
|
|
CLIENT *cl, *clnt_create();
|
|
char *server = "";
|
|
int mapi = 0;
|
|
|
|
yp_get_default_domain (&dom);
|
|
while (!strcmp("", server) && aliases[mapi].map != 0L) {
|
|
yp_master (dom, aliases[mapi].map, &server);
|
|
mapi++;
|
|
}
|
|
if (!strcmp("", server)) {
|
|
PyErr_SetString(NisError, "No NIS master found for any map");
|
|
return NULL;
|
|
}
|
|
cl = clnt_create(server, YPPROG, YPVERS, "tcp");
|
|
if (cl == NULL) {
|
|
PyErr_SetString(NisError, clnt_spcreateerror(server));
|
|
return NULL;
|
|
}
|
|
list = nisproc_maplist_2 (&dom, cl);
|
|
if (list == NULL)
|
|
return NULL;
|
|
if (list->stat != NIS_TRUE)
|
|
return NULL;
|
|
return list->maps;
|
|
}
|
|
|
|
static PyObject *
|
|
nis_maps (self, args)
|
|
PyObject *self;
|
|
PyObject *args;
|
|
{
|
|
nismaplist *maps;
|
|
PyObject *list;
|
|
|
|
if ((maps = nis_maplist ()) == NULL)
|
|
return NULL;
|
|
if ((list = PyList_New(0)) == NULL)
|
|
return NULL;
|
|
for (maps = maps->next; maps; maps = maps->next) {
|
|
if (PyList_Append (list, PyString_FromString (maps->map)) < 0)
|
|
{
|
|
Py_DECREF(list);
|
|
list = NULL;
|
|
break;
|
|
}
|
|
}
|
|
/* XXX Shouldn't we free the list of maps now? */
|
|
return list;
|
|
}
|
|
|
|
static PyMethodDef nis_methods[] = {
|
|
{"match", nis_match},
|
|
{"cat", nis_cat},
|
|
{"maps", nis_maps},
|
|
{NULL, NULL} /* Sentinel */
|
|
};
|
|
|
|
void
|
|
initnis ()
|
|
{
|
|
PyObject *m, *d;
|
|
m = Py_InitModule("nis", nis_methods);
|
|
d = PyModule_GetDict(m);
|
|
NisError = PyString_FromString("nis.error");
|
|
if (NisError == NULL ||
|
|
PyDict_SetItemString(d, "error", NisError) != 0)
|
|
Py_FatalError("Cannot define nis.error");
|
|
}
|