LCOV - code coverage report
Current view: top level - Modules - nismodule.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 33 191 17.3 %
Date: 2022-07-07 18:19:46 Functions: 8 20 40.0 %

          Line data    Source code
       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 <stdlib.h>               // free()
      16             : #include <sys/time.h>
      17             : #include <sys/types.h>
      18             : #include <rpc/rpc.h>
      19             : #include <rpcsvc/yp_prot.h>
      20             : #include <rpcsvc/ypclnt.h>
      21             : 
      22             : #ifdef __sgi
      23             : /* This is missing from rpcsvc/ypclnt.h */
      24             : extern int yp_get_default_domain(char **);
      25             : #endif
      26             : 
      27             : PyDoc_STRVAR(get_default_domain__doc__,
      28             : "get_default_domain() -> str\n\
      29             : Corresponds to the C library yp_get_default_domain() call, returning\n\
      30             : the default NIS domain.\n");
      31             : 
      32             : PyDoc_STRVAR(match__doc__,
      33             : "match(key, map, domain = defaultdomain)\n\
      34             : Corresponds to the C library yp_match() call, returning the value of\n\
      35             : key in the given map. Optionally domain can be specified but it\n\
      36             : defaults to the system default domain.\n");
      37             : 
      38             : PyDoc_STRVAR(cat__doc__,
      39             : "cat(map, domain = defaultdomain)\n\
      40             : Returns the entire map as a dictionary. Optionally domain can be\n\
      41             : specified but it defaults to the system default domain.\n");
      42             : 
      43             : PyDoc_STRVAR(maps__doc__,
      44             : "maps(domain = defaultdomain)\n\
      45             : Returns an array of all available NIS maps within a domain. If domain\n\
      46             : is not specified it defaults to the system default domain.\n");
      47             : 
      48             : typedef struct {
      49             :     PyObject *nis_error;
      50             : } nis_state;
      51             : 
      52             : static inline nis_state*
      53          65 : get_nis_state(PyObject *module)
      54             : {
      55          65 :     void *state = PyModule_GetState(module);
      56          65 :     assert(state != NULL);
      57          65 :     return (nis_state *)state;
      58             : }
      59             : 
      60             : static int
      61           4 : nis_clear(PyObject *m)
      62             : {
      63           4 :     Py_CLEAR(get_nis_state(m)->nis_error);
      64           4 :     return 0;
      65             : }
      66             : 
      67             : static int
      68          28 : nis_traverse(PyObject *m, visitproc visit, void *arg)
      69             : {
      70          28 :     Py_VISIT(get_nis_state(m)->nis_error);
      71          28 :     return 0;
      72             : }
      73             : 
      74             : static void
      75           2 : nis_free(void *m)
      76             : {
      77           2 :     nis_clear((PyObject *) m);
      78           2 : }
      79             : 
      80             : static PyObject *
      81           1 : nis_error(nis_state *state, int err)
      82             : {
      83           1 :     PyErr_SetString(state->nis_error, yperr_string(err));
      84           1 :     return NULL;
      85             : }
      86             : 
      87             : static struct nis_map {
      88             :     char *alias;
      89             :     char *map;
      90             :     int  fix;
      91             : } aliases [] = {
      92             :     {"passwd",          "passwd.byname",        0},
      93             :     {"group",           "group.byname",         0},
      94             :     {"networks",        "networks.byaddr",      0},
      95             :     {"hosts",           "hosts.byname",         0},
      96             :     {"protocols",       "protocols.bynumber",   0},
      97             :     {"services",        "services.byname",      0},
      98             :     {"aliases",         "mail.aliases",         1}, /* created with 'makedbm -a' */
      99             :     {"ethers",          "ethers.byname",        0},
     100             :     {0L,                0L,                     0}
     101             : };
     102             : 
     103             : static char *
     104           0 : nis_mapname(char *map, int *pfix)
     105             : {
     106             :     int i;
     107             : 
     108           0 :     *pfix = 0;
     109           0 :     for (i=0; aliases[i].alias != 0L; i++) {
     110           0 :         if (!strcmp (aliases[i].alias, map) || !strcmp (aliases[i].map, map)) {
     111           0 :             *pfix = aliases[i].fix;
     112           0 :             return aliases[i].map;
     113             :         }
     114             :     }
     115             : 
     116           0 :     return map;
     117             : }
     118             : 
     119             : #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
     120             : typedef int (*foreachfunc)(unsigned long, char *, int, char *, int, void *);
     121             : #else
     122             : typedef int (*foreachfunc)(int, char *, int, char *, int, char *);
     123             : #endif
     124             : 
     125             : struct ypcallback_data {
     126             :     PyObject            *dict;
     127             :     int                         fix;
     128             :     PyThreadState *state;
     129             : };
     130             : 
     131             : static int
     132           0 : nis_foreach(int instatus, char *inkey, int inkeylen, char *inval,
     133             :              int invallen, struct ypcallback_data *indata)
     134             : {
     135           0 :     if (instatus == YP_TRUE) {
     136             :         PyObject *key;
     137             :         PyObject *val;
     138             :         int err;
     139             : 
     140           0 :         PyEval_RestoreThread(indata->state);
     141           0 :         if (indata->fix) {
     142           0 :             if (inkeylen > 0 && inkey[inkeylen-1] == '\0')
     143           0 :             inkeylen--;
     144           0 :             if (invallen > 0 && inval[invallen-1] == '\0')
     145           0 :             invallen--;
     146             :         }
     147           0 :         key = PyUnicode_DecodeFSDefaultAndSize(inkey, inkeylen);
     148           0 :         val = PyUnicode_DecodeFSDefaultAndSize(inval, invallen);
     149           0 :         if (key == NULL || val == NULL) {
     150             :             /* XXX error -- don't know how to handle */
     151           0 :             PyErr_Clear();
     152           0 :             Py_XDECREF(key);
     153           0 :             Py_XDECREF(val);
     154           0 :             indata->state = PyEval_SaveThread();
     155           0 :             return 1;
     156             :         }
     157           0 :         err = PyDict_SetItem(indata->dict, key, val);
     158           0 :         Py_DECREF(key);
     159           0 :         Py_DECREF(val);
     160           0 :         if (err != 0)
     161           0 :             PyErr_Clear();
     162           0 :         indata->state = PyEval_SaveThread();
     163           0 :         if (err != 0)
     164           0 :             return 1;
     165           0 :         return 0;
     166             :     }
     167           0 :     return 1;
     168             : }
     169             : 
     170             : static PyObject *
     171           0 : nis_get_default_domain(PyObject *module, PyObject *Py_UNUSED(ignored))
     172             : {
     173             :     char *domain;
     174             :     int err;
     175             :     PyObject *res;
     176           0 :     nis_state *state = get_nis_state(module);
     177           0 :     if ((err = yp_get_default_domain(&domain)) != 0) {
     178           0 :         return nis_error(state, err);
     179             :     }
     180             : 
     181           0 :     res = PyUnicode_FromStringAndSize (domain, strlen(domain));
     182           0 :     return res;
     183             : }
     184             : 
     185             : static PyObject *
     186           0 : nis_match(PyObject *module, PyObject *args, PyObject *kwdict)
     187             : {
     188             :     char *match;
     189           0 :     char *domain = NULL;
     190             :     Py_ssize_t keylen;
     191             :     int len;
     192             :     char *key, *map;
     193             :     int err;
     194             :     PyObject *ukey, *bkey, *res;
     195             :     int fix;
     196             :     static char *kwlist[] = {"key", "map", "domain", NULL};
     197             : 
     198           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwdict,
     199             :                                      "Us|s:match", kwlist,
     200             :                                      &ukey, &map, &domain)) {
     201           0 :         return NULL;
     202             :     }
     203           0 :     if ((bkey = PyUnicode_EncodeFSDefault(ukey)) == NULL) {
     204           0 :         return NULL;
     205             :     }
     206             :     /* check for embedded null bytes */
     207           0 :     if (PyBytes_AsStringAndSize(bkey, &key, &keylen) == -1) {
     208           0 :         Py_DECREF(bkey);
     209           0 :         return NULL;
     210             :     }
     211             : 
     212           0 :     nis_state *state = get_nis_state(module);
     213           0 :     if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) {
     214           0 :         Py_DECREF(bkey);
     215           0 :         return nis_error(state, err);
     216             :     }
     217           0 :     map = nis_mapname (map, &fix);
     218           0 :     if (fix)
     219           0 :         keylen++;
     220           0 :     Py_BEGIN_ALLOW_THREADS
     221           0 :     err = yp_match (domain, map, key, keylen, &match, &len);
     222           0 :     Py_END_ALLOW_THREADS
     223           0 :     Py_DECREF(bkey);
     224           0 :     if (fix)
     225           0 :         len--;
     226           0 :     if (err != 0) {
     227           0 :         return nis_error(state, err);
     228             :     }
     229           0 :     res = PyUnicode_DecodeFSDefaultAndSize(match, len);
     230           0 :     free (match);
     231           0 :     return res;
     232             : }
     233             : 
     234             : static PyObject *
     235           0 : nis_cat(PyObject *module, PyObject *args, PyObject *kwdict)
     236             : {
     237           0 :     char *domain = NULL;
     238             :     char *map;
     239             :     struct ypall_callback cb;
     240             :     struct ypcallback_data data;
     241             :     PyObject *dict;
     242             :     int err;
     243             :     static char *kwlist[] = {"map", "domain", NULL};
     244             : 
     245           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat",
     246             :                                      kwlist, &map, &domain)) {
     247           0 :         return NULL;
     248             :     }
     249           0 :     nis_state *state = get_nis_state(module);
     250           0 :     if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) {
     251           0 :         return nis_error(state, err);
     252             :     }
     253           0 :     dict = PyDict_New ();
     254           0 :     if (dict == NULL)
     255           0 :         return NULL;
     256           0 :     cb.foreach = (foreachfunc)nis_foreach;
     257           0 :     data.dict = dict;
     258           0 :     map = nis_mapname (map, &data.fix);
     259           0 :     cb.data = (char *)&data;
     260           0 :     data.state = PyEval_SaveThread();
     261           0 :     err = yp_all (domain, map, &cb);
     262           0 :     PyEval_RestoreThread(data.state);
     263           0 :     if (err != 0) {
     264           0 :         Py_DECREF(dict);
     265           0 :         return nis_error(state, err);
     266             :     }
     267           0 :     return dict;
     268             : }
     269             : 
     270             : /* These should be u_long on Sun h/w but not on 64-bit h/w.
     271             :    This is not portable to machines with 16-bit ints and no prototypes */
     272             : #ifndef YPPROC_MAPLIST
     273             : #define YPPROC_MAPLIST  11
     274             : #endif
     275             : #ifndef YPPROG
     276             : #define YPPROG          100004
     277             : #endif
     278             : #ifndef YPVERS
     279             : #define YPVERS          2
     280             : #endif
     281             : 
     282             : typedef char *domainname;
     283             : typedef char *mapname;
     284             : 
     285             : enum nisstat {
     286             :     NIS_TRUE = 1,
     287             :     NIS_NOMORE = 2,
     288             :     NIS_FALSE = 0,
     289             :     NIS_NOMAP = -1,
     290             :     NIS_NODOM = -2,
     291             :     NIS_NOKEY = -3,
     292             :     NIS_BADOP = -4,
     293             :     NIS_BADDB = -5,
     294             :     NIS_YPERR = -6,
     295             :     NIS_BADARGS = -7,
     296             :     NIS_VERS = -8
     297             : };
     298             : typedef enum nisstat nisstat;
     299             : 
     300             : struct nismaplist {
     301             :     mapname map;
     302             :     struct nismaplist *next;
     303             : };
     304             : typedef struct nismaplist nismaplist;
     305             : 
     306             : struct nisresp_maplist {
     307             :     nisstat stat;
     308             :     nismaplist *maps;
     309             : };
     310             : typedef struct nisresp_maplist nisresp_maplist;
     311             : 
     312             : static struct timeval TIMEOUT = { 25, 0 };
     313             : 
     314             : static
     315             : bool_t
     316           0 : nis_xdr_domainname(XDR *xdrs, domainname *objp)
     317             : {
     318           0 :     if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
     319           0 :         return (FALSE);
     320             :     }
     321           0 :     return (TRUE);
     322             : }
     323             : 
     324             : static
     325             : bool_t
     326           0 : nis_xdr_mapname(XDR *xdrs, mapname *objp)
     327             : {
     328           0 :     if (!xdr_string(xdrs, objp, YPMAXMAP)) {
     329           0 :         return (FALSE);
     330             :     }
     331           0 :     return (TRUE);
     332             : }
     333             : 
     334             : static
     335             : bool_t
     336           0 : nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp)
     337             : {
     338           0 :     if (!nis_xdr_mapname(xdrs, &objp->map)) {
     339           0 :         return (FALSE);
     340             :     }
     341           0 :     if (!xdr_pointer(xdrs, (char **)&objp->next,
     342             :                      sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
     343             :     {
     344           0 :         return (FALSE);
     345             :     }
     346           0 :     return (TRUE);
     347             : }
     348             : 
     349             : static
     350             : bool_t
     351           0 : nis_xdr_ypstat(XDR *xdrs, nisstat *objp)
     352             : {
     353           0 :     if (!xdr_enum(xdrs, (enum_t *)objp)) {
     354           0 :         return (FALSE);
     355             :     }
     356           0 :     return (TRUE);
     357             : }
     358             : 
     359             : 
     360             : static
     361             : bool_t
     362           0 : nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp)
     363             : {
     364           0 :     if (!nis_xdr_ypstat(xdrs, &objp->stat)) {
     365           0 :         return (FALSE);
     366             :     }
     367           0 :     if (!xdr_pointer(xdrs, (char **)&objp->maps,
     368             :                      sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist))
     369             :     {
     370           0 :         return (FALSE);
     371             :     }
     372           0 :     return (TRUE);
     373             : }
     374             : 
     375             : 
     376             : static
     377             : nisresp_maplist *
     378           0 : nisproc_maplist_2(domainname *argp, CLIENT *clnt)
     379             : {
     380             :     static nisresp_maplist res;
     381             : 
     382           0 :     memset(&res, 0, sizeof(res));
     383           0 :     if (clnt_call(clnt, YPPROC_MAPLIST,
     384             :                   (xdrproc_t)nis_xdr_domainname, (caddr_t)argp,
     385             :                   (xdrproc_t)nis_xdr_ypresp_maplist, (caddr_t)&res,
     386             :                   TIMEOUT) != RPC_SUCCESS)
     387             :     {
     388           0 :         return (NULL);
     389             :     }
     390           0 :     return (&res);
     391             : }
     392             : 
     393             : static
     394             : nismaplist *
     395           0 : nis_maplist(nis_state *state, char *dom)
     396             : {
     397             :     nisresp_maplist *list;
     398             :     CLIENT *cl;
     399           0 :     char *server = NULL;
     400           0 :     int mapi = 0;
     401             : 
     402           0 :     while (!server && aliases[mapi].map != 0L) {
     403           0 :         yp_master (dom, aliases[mapi].map, &server);
     404           0 :         mapi++;
     405             :     }
     406           0 :     if (!server) {
     407           0 :         PyErr_SetString(state->nis_error, "No NIS master found for any map");
     408           0 :         return NULL;
     409             :     }
     410           0 :     cl = clnt_create(server, YPPROG, YPVERS, "tcp");
     411           0 :     if (cl == NULL) {
     412           0 :         PyErr_SetString(state->nis_error, clnt_spcreateerror(server));
     413           0 :         goto finally;
     414             :     }
     415           0 :     list = nisproc_maplist_2 (&dom, cl);
     416           0 :     clnt_destroy(cl);
     417           0 :     if (list == NULL)
     418           0 :         goto finally;
     419           0 :     if (list->stat != NIS_TRUE)
     420           0 :         goto finally;
     421             : 
     422           0 :     free(server);
     423           0 :     return list->maps;
     424             : 
     425           0 :   finally:
     426           0 :     free(server);
     427           0 :     return NULL;
     428             : }
     429             : 
     430             : static PyObject *
     431           1 : nis_maps (PyObject *module, PyObject *args, PyObject *kwdict)
     432             : {
     433           1 :     char *domain = NULL;
     434             :     nismaplist *maps;
     435             :     PyObject *list;
     436             :     int err;
     437             :     static char *kwlist[] = {"domain", NULL};
     438             : 
     439           1 :     if (!PyArg_ParseTupleAndKeywords(args, kwdict,
     440             :                                      "|s:maps", kwlist, &domain)) {
     441           0 :         return NULL;
     442             :     }
     443             : 
     444           1 :     nis_state *state = get_nis_state(module);
     445           1 :     if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) {
     446           1 :         nis_error(state, err);
     447           1 :         return NULL;
     448             :     }
     449             : 
     450           0 :     if ((maps = nis_maplist(state, domain)) == NULL) {
     451           0 :         return NULL;
     452             :     }
     453           0 :     if ((list = PyList_New(0)) == NULL) {
     454           0 :         return NULL;
     455             :     }
     456           0 :     for (; maps; maps = maps->next) {
     457           0 :         PyObject *str = PyUnicode_FromString(maps->map);
     458           0 :         if (!str || PyList_Append(list, str) < 0)
     459             :         {
     460           0 :             Py_XDECREF(str);
     461           0 :             Py_DECREF(list);
     462           0 :             list = NULL;
     463           0 :             break;
     464             :         }
     465           0 :         Py_DECREF(str);
     466             :     }
     467             :     /* XXX Shouldn't we free the list of maps now? */
     468           0 :     return list;
     469             : }
     470             : 
     471             : static PyMethodDef nis_methods[] = {
     472             :     {"match",                   _PyCFunction_CAST(nis_match),
     473             :                                     METH_VARARGS | METH_KEYWORDS,
     474             :                                     match__doc__},
     475             :     {"cat",                     _PyCFunction_CAST(nis_cat),
     476             :                                     METH_VARARGS | METH_KEYWORDS,
     477             :                                     cat__doc__},
     478             :     {"maps",                    _PyCFunction_CAST(nis_maps),
     479             :                                     METH_VARARGS | METH_KEYWORDS,
     480             :                                     maps__doc__},
     481             :     {"get_default_domain",      nis_get_default_domain,
     482             :                                     METH_NOARGS,
     483             :                                     get_default_domain__doc__},
     484             :     {NULL,                      NULL}            /* Sentinel */
     485             : };
     486             : 
     487             : static int
     488           2 : nis_exec(PyObject *module)
     489             : {
     490           2 :     nis_state* state = get_nis_state(module);
     491           2 :     state->nis_error = PyErr_NewException("nis.error", NULL, NULL);
     492           2 :     if (state->nis_error == NULL) {
     493           0 :         return -1;
     494             :     }
     495             : 
     496           2 :     Py_INCREF(state->nis_error);
     497           2 :     if (PyModule_AddObject(module, "error", state->nis_error) < 0) {
     498           0 :         Py_DECREF(state->nis_error);
     499           0 :         return -1;
     500             :     }
     501           2 :     return 0;
     502             : }
     503             : 
     504             : static PyModuleDef_Slot nis_slots[] = {
     505             :     {Py_mod_exec, nis_exec},
     506             :     {0, NULL}
     507             : };
     508             : 
     509             : PyDoc_STRVAR(nis__doc__,
     510             : "This module contains functions for accessing NIS maps.\n");
     511             : 
     512             : static struct PyModuleDef nismodule = {
     513             :     PyModuleDef_HEAD_INIT,
     514             :     .m_name = "nis",
     515             :     .m_doc = nis__doc__,
     516             :     .m_size = sizeof(nis_state),
     517             :     .m_methods = nis_methods,
     518             :     .m_traverse = nis_traverse,
     519             :     .m_clear = nis_clear,
     520             :     .m_free = nis_free,
     521             :     .m_slots = nis_slots,
     522             : };
     523             : 
     524             : PyMODINIT_FUNC
     525           2 : PyInit_nis(void)
     526             : {
     527           2 :     if (PyErr_WarnEx(PyExc_DeprecationWarning,
     528             :                      "'nis' is deprecated and slated for removal in "
     529             :                      "Python 3.13",
     530             :                      7)) {
     531           0 :         return NULL;
     532             :     }
     533           2 :     return PyModuleDef_Init(&nismodule);
     534             : }

Generated by: LCOV version 1.14