Skip to content

bpo-40950: Port nis module to multiphase initialization #20811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add a state to the :mod:`nis` module (:pep:`3121`) and apply
the multiphase initialization. Patch by Dong-hee Na.
148 changes: 103 additions & 45 deletions Modules/nismodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,42 @@ PyDoc_STRVAR(maps__doc__,
Returns an array of all available NIS maps within a domain. If domain\n\
is not specified it defaults to the system default domain.\n");

static PyObject *NisError;
typedef struct {
PyObject *nis_error;
} nis_state;

static inline nis_state*
get_nis_state(PyObject *module)
{
void *state = PyModule_GetState(module);
assert(state != NULL);
return (nis_state *)state;
}

static int
nis_clear(PyObject *m)
{
Py_CLEAR(get_nis_state(m)->nis_error);
return 0;
}

static int
nis_traverse(PyObject *m, visitproc visit, void *arg)
{
Py_VISIT(get_nis_state(m)->nis_error);
return 0;
}

static void
nis_free(void *m)
{
nis_clear((PyObject *) m);
}

static PyObject *
nis_error (int err)
nis_error(nis_state *state, int err)
{
PyErr_SetString(NisError, yperr_string(err));
PyErr_SetString(state->nis_error, yperr_string(err));
return NULL;
}

Expand All @@ -70,7 +100,7 @@ static struct nis_map {
};

static char *
nis_mapname (char *map, int *pfix)
nis_mapname(char *map, int *pfix)
{
int i;

Expand Down Expand Up @@ -98,7 +128,7 @@ struct ypcallback_data {
};

static int
nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
nis_foreach(int instatus, char *inkey, int inkeylen, char *inval,
int invallen, struct ypcallback_data *indata)
{
if (instatus == YP_TRUE) {
Expand Down Expand Up @@ -137,21 +167,22 @@ nis_foreach (int instatus, char *inkey, int inkeylen, char *inval,
}

static PyObject *
nis_get_default_domain (PyObject *self, PyObject *Py_UNUSED(ignored))
nis_get_default_domain(PyObject *module, PyObject *Py_UNUSED(ignored))
{
char *domain;
int err;
PyObject *res;

if ((err = yp_get_default_domain(&domain)) != 0)
return nis_error(err);
nis_state *state = get_nis_state(module);
if ((err = yp_get_default_domain(&domain)) != 0) {
return nis_error(state, err);
}

res = PyUnicode_FromStringAndSize (domain, strlen(domain));
return res;
}

static PyObject *
nis_match (PyObject *self, PyObject *args, PyObject *kwdict)
nis_match(PyObject *module, PyObject *args, PyObject *kwdict)
{
char *match;
char *domain = NULL;
Expand All @@ -165,18 +196,22 @@ nis_match (PyObject *self, PyObject *args, PyObject *kwdict)

if (!PyArg_ParseTupleAndKeywords(args, kwdict,
"Us|s:match", kwlist,
&ukey, &map, &domain))
&ukey, &map, &domain)) {
return NULL;
if ((bkey = PyUnicode_EncodeFSDefault(ukey)) == NULL)
}
if ((bkey = PyUnicode_EncodeFSDefault(ukey)) == NULL) {
return NULL;
}
/* check for embedded null bytes */
if (PyBytes_AsStringAndSize(bkey, &key, &keylen) == -1) {
Py_DECREF(bkey);
return NULL;
}

nis_state *state = get_nis_state(module);
if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) {
Py_DECREF(bkey);
return nis_error(err);
return nis_error(state, err);
}
map = nis_mapname (map, &fix);
if (fix)
Expand All @@ -187,15 +222,16 @@ nis_match (PyObject *self, PyObject *args, PyObject *kwdict)
Py_DECREF(bkey);
if (fix)
len--;
if (err != 0)
return nis_error(err);
if (err != 0) {
return nis_error(state, err);
}
res = PyUnicode_DecodeFSDefaultAndSize(match, len);
free (match);
return res;
}

static PyObject *
nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
nis_cat(PyObject *module, PyObject *args, PyObject *kwdict)
{
char *domain = NULL;
char *map;
Expand All @@ -206,10 +242,13 @@ nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
static char *kwlist[] = {"map", "domain", NULL};

if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat",
kwlist, &map, &domain))
kwlist, &map, &domain)) {
return NULL;
if (!domain && ((err = yp_get_default_domain(&domain)) != 0))
return nis_error(err);
}
nis_state *state = get_nis_state(module);
if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) {
return nis_error(state, err);
}
dict = PyDict_New ();
if (dict == NULL)
return NULL;
Expand All @@ -222,7 +261,7 @@ nis_cat (PyObject *self, PyObject *args, PyObject *kwdict)
PyEval_RestoreThread(data.state);
if (err != 0) {
Py_DECREF(dict);
return nis_error(err);
return nis_error(state, err);
}
return dict;
}
Expand Down Expand Up @@ -352,7 +391,7 @@ nisproc_maplist_2(domainname *argp, CLIENT *clnt)

static
nismaplist *
nis_maplist (char *dom)
nis_maplist(nis_state *state, char *dom)
{
nisresp_maplist *list;
CLIENT *cl;
Expand All @@ -364,12 +403,12 @@ nis_maplist (char *dom)
mapi++;
}
if (!server) {
PyErr_SetString(NisError, "No NIS master found for any map");
PyErr_SetString(state->nis_error, "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));
PyErr_SetString(state->nis_error, clnt_spcreateerror(server));
goto finally;
}
list = nisproc_maplist_2 (&dom, cl);
Expand All @@ -388,7 +427,7 @@ nis_maplist (char *dom)
}

static PyObject *
nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
nis_maps (PyObject *module, PyObject *args, PyObject *kwdict)
{
char *domain = NULL;
nismaplist *maps;
Expand All @@ -397,17 +436,22 @@ nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
static char *kwlist[] = {"domain", NULL};

if (!PyArg_ParseTupleAndKeywords(args, kwdict,
"|s:maps", kwlist, &domain))
"|s:maps", kwlist, &domain)) {
return NULL;
}

nis_state *state = get_nis_state(module);
if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) {
nis_error(err);
nis_error(state, err);
return NULL;
}

if ((maps = nis_maplist (domain)) == NULL)
if ((maps = nis_maplist(state, domain)) == NULL) {
return NULL;
if ((list = PyList_New(0)) == NULL)
}
if ((list = PyList_New(0)) == NULL) {
return NULL;
}
for (; maps; maps = maps->next) {
PyObject *str = PyUnicode_FromString(maps->map);
if (!str || PyList_Append(list, str) < 0)
Expand Down Expand Up @@ -439,31 +483,45 @@ static PyMethodDef nis_methods[] = {
{NULL, NULL} /* Sentinel */
};

static int
nis_exec(PyObject *module)
{
nis_state* state = get_nis_state(module);
state->nis_error = PyErr_NewException("nis.error", NULL, NULL);
if (state->nis_error == NULL) {
return -1;
}

Py_INCREF(state->nis_error);
if (PyModule_AddObject(module, "error", state->nis_error) < 0) {
Py_DECREF(state->nis_error);
return -1;
}
return 0;
}

static PyModuleDef_Slot nis_slots[] = {
{Py_mod_exec, nis_exec},
{0, NULL}
};

PyDoc_STRVAR(nis__doc__,
"This module contains functions for accessing NIS maps.\n");

static struct PyModuleDef nismodule = {
PyModuleDef_HEAD_INIT,
"nis",
nis__doc__,
-1,
nis_methods,
NULL,
NULL,
NULL,
NULL
.m_name = "nis",
.m_doc = nis__doc__,
.m_size = sizeof(nis_state),
.m_methods = nis_methods,
.m_traverse = nis_traverse,
.m_clear = nis_clear,
.m_free = nis_free,
.m_slots = nis_slots,
};

PyMODINIT_FUNC
PyInit_nis(void)
{
PyObject *m, *d;
m = PyModule_Create(&nismodule);
if (m == NULL)
return NULL;
d = PyModule_GetDict(m);
NisError = PyErr_NewException("nis.error", NULL, NULL);
if (NisError != NULL)
PyDict_SetItemString(d, "error", NisError);
return m;
return PyModuleDef_Init(&nismodule);
}