LCOV - code coverage report
Current view: top level - python - pysss.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 429 0.0 %
Date: 2015-10-19 Functions: 0 18 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Jakub Hrozek <jhrozek@redhat.com>
       4             : 
       5             :     Copyright (C) 2009 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <Python.h>
      22             : #include <structmember.h>
      23             : #include <talloc.h>
      24             : #include <pwd.h>
      25             : #include <grp.h>
      26             : 
      27             : #include "util/util.h"
      28             : #include "util/sss_python.h"
      29             : #include "db/sysdb.h"
      30             : #include "tools/tools_util.h"
      31             : #include "tools/sss_sync_ops.h"
      32             : #include "util/crypto/sss_crypto.h"
      33             : 
      34             : /*
      35             :  * function taken from samba sources tree as of Aug 20 2009,
      36             :  * file source4/lib/ldb/pyldb.c
      37             :  */
      38           0 : static char **PyList_AsStringList(TALLOC_CTX *mem_ctx, PyObject *list,
      39             :                                   const char *paramname)
      40             : {
      41             :     char **ret;
      42             :     int i;
      43             : 
      44           0 :     ret = talloc_array(mem_ctx, char *, PyList_Size(list)+1);
      45           0 :     for (i = 0; i < PyList_Size(list); i++) {
      46             :         char *itemstr;
      47             :         Py_ssize_t itemlen;
      48           0 :         PyObject *item = PyList_GetItem(list, i);
      49             : #ifdef IS_PY3K
      50           0 :         if (!PyUnicode_Check(item)) {
      51             : #else
      52           0 :         if (!PyString_Check(item)) {
      53             : #endif
      54           0 :             PyErr_Format(PyExc_TypeError, "%s should be strings", paramname);
      55           0 :             return NULL;
      56             :         }
      57             : #ifdef IS_PY3K
      58           0 :         itemstr = PyUnicode_AsUTF8AndSize(item, &itemlen);
      59             : #else
      60           0 :         itemstr = PyString_AsString(item);
      61           0 :         itemlen = strlen(itemstr);
      62             : #endif
      63           0 :         ret[i] = talloc_strndup(ret, itemstr, itemlen);
      64             :     }
      65             : 
      66           0 :     ret[i] = NULL;
      67           0 :     return ret;
      68             : }
      69             : 
      70             : /* ======================= sysdb python wrappers ==========================*/
      71             : 
      72             : /*
      73             :  * The sss.password object
      74             :  */
      75             : typedef struct {
      76             :     PyObject_HEAD
      77             : 
      78             :     TALLOC_CTX *mem_ctx;
      79             :     struct tevent_context *ev;
      80             :     struct sysdb_ctx *sysdb;
      81             :     struct confdb_ctx *confdb;
      82             : 
      83             :     struct sss_domain_info *local;
      84             : 
      85             :     int lock;
      86             :     int unlock;
      87             : } PySssLocalObject;
      88             : 
      89             : /*
      90             :  * Error reporting
      91             :  */
      92           0 : static void PyErr_SetSssErrorWithMessage(int ret, const char *message)
      93             : {
      94           0 :     PyObject *exc = Py_BuildValue(discard_const_p(char, "(is)"),
      95             :                                   ret, message);
      96             : 
      97           0 :     PyErr_SetObject(PyExc_IOError, exc);
      98           0 :     Py_XDECREF(exc);
      99           0 : }
     100             : 
     101           0 : static void PyErr_SetSssError(int ret)
     102             : {
     103           0 :     PyErr_SetSssErrorWithMessage(ret, strerror(ret));
     104           0 : }
     105             : 
     106             : /*
     107             :  * Common init of all methods
     108             :  */
     109           0 : static struct tools_ctx *init_ctx(PySssLocalObject *self)
     110             : {
     111           0 :     struct ops_ctx *octx = NULL;
     112           0 :     struct tools_ctx *tctx = NULL;
     113             : 
     114           0 :     tctx = talloc_zero(self->mem_ctx, struct tools_ctx);
     115           0 :     if (tctx == NULL) {
     116           0 :         return NULL;
     117             :     }
     118             : 
     119           0 :     tctx->confdb = self->confdb;
     120           0 :     tctx->sysdb = self->sysdb;
     121           0 :     tctx->local = self->local;
     122             :     /* tctx->nctx is NULL here, which is OK since we don't parse domains
     123             :      * in the python bindings (yet?) */
     124             : 
     125           0 :     octx = talloc_zero(tctx, struct ops_ctx);
     126           0 :     if (octx == NULL) {
     127           0 :         PyErr_NoMemory();
     128           0 :         return NULL;
     129             :     }
     130           0 :     octx->domain = self->local;
     131             : 
     132           0 :     tctx->octx = octx;
     133           0 :     return tctx;
     134             : }
     135             : 
     136             : /*
     137             :  * Add a user
     138             :  */
     139             : PyDoc_STRVAR(py_sss_useradd__doc__,
     140             :     "Add a user named ``username``.\n\n"
     141             :     ":param username: name of the user\n\n"
     142             :     ":param kwargs: Keyword arguments that customize the operation\n\n"
     143             :     "* useradd can be customized further with keyword arguments:\n"
     144             :     "    * ``uid``: The UID of the user\n"
     145             :     "    * ``gid``: The GID of the user\n"
     146             :     "    * ``gecos``: The comment string\n"
     147             :     "    * ``homedir``: Home directory\n"
     148             :     "    * ``shell``: Login shell\n"
     149             :     "    * ``skel``: Specify an alternative skeleton directory\n"
     150             :     "    * ``create_home``: (bool) Force creation of home directory on or off\n"
     151             :     "    * ``groups``: List of groups the user is member of\n");
     152             : 
     153             : 
     154           0 : static PyObject *py_sss_useradd(PySssLocalObject *self,
     155             :                                 PyObject *args,
     156             :                                 PyObject *kwds)
     157             : {
     158           0 :     struct tools_ctx *tctx = NULL;
     159           0 :     unsigned long uid = 0;
     160           0 :     unsigned long gid = 0;
     161           0 :     const char *gecos = NULL;
     162           0 :     const char *home = NULL;
     163           0 :     const char *shell = NULL;
     164           0 :     const char *skel = NULL;
     165           0 :     char *username = NULL;
     166             :     int ret;
     167           0 :     const char * const kwlist[] = { "username", "uid", "gid", "gecos",
     168             :                                     "homedir", "shell", "skel",
     169             :                                     "create_home", "groups", NULL };
     170           0 :     PyObject *py_groups = Py_None;
     171           0 :     PyObject *py_create_home = Py_None;
     172           0 :     int create_home = 0;
     173           0 :     bool in_transaction = false;
     174             : 
     175             :     /* parse arguments */
     176           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
     177             :                                      discard_const_p(char, "s|kkssssO!O!"),
     178             :                                      discard_const_p(char *, kwlist),
     179             :                                      &username,
     180             :                                      &uid,
     181             :                                      &gid,
     182             :                                      &gecos,
     183             :                                      &home,
     184             :                                      &shell,
     185             :                                      &skel,
     186             :                                      &PyBool_Type,
     187             :                                      &py_create_home,
     188             :                                      &PyList_Type,
     189             :                                      &py_groups)) {
     190           0 :         goto fail;
     191             :     }
     192             : 
     193           0 :     tctx = init_ctx(self);
     194           0 :     if (!tctx) {
     195           0 :         PyErr_NoMemory();
     196           0 :         return NULL;
     197             :     }
     198             : 
     199           0 :     if (py_groups != Py_None) {
     200           0 :         tctx->octx->addgroups = PyList_AsStringList(tctx, py_groups, "groups");
     201           0 :         if (!tctx->octx->addgroups) {
     202           0 :             PyErr_NoMemory();
     203           0 :             return NULL;
     204             :         }
     205             :     }
     206             : 
     207             :     /* user-wise the parameter is only bool - do or don't,
     208             :      * however we must have a third state - undecided, pick default */
     209           0 :     if (py_create_home == Py_True) {
     210           0 :         create_home = DO_CREATE_HOME;
     211           0 :     } else if (py_create_home == Py_False) {
     212           0 :         create_home = DO_NOT_CREATE_HOME;
     213             :     }
     214             : 
     215           0 :     tctx->octx->name = username;
     216           0 :     tctx->octx->uid = uid;
     217             : 
     218             :     /* fill in defaults */
     219           0 :     ret = useradd_defaults(tctx,
     220             :                            self->confdb,
     221             :                            tctx->octx, gecos,
     222             :                            home, shell,
     223             :                            create_home,
     224             :                            skel);
     225           0 :     if (ret != EOK) {
     226           0 :         PyErr_SetSssError(ret);
     227           0 :         goto fail;
     228             :     }
     229             : 
     230             :     /* Add the user within a transaction */
     231           0 :     tctx->error = sysdb_transaction_start(tctx->sysdb);
     232           0 :     if (tctx->error != EOK) {
     233           0 :         PyErr_SetSssError(tctx->error);
     234           0 :         goto fail;
     235             :     }
     236           0 :     in_transaction = true;
     237             : 
     238             :     /* useradd */
     239           0 :     tctx->error = useradd(tctx, tctx->octx);
     240           0 :     if (tctx->error) {
     241           0 :         PyErr_SetSssError(tctx->error);
     242           0 :         goto fail;
     243             :     }
     244             : 
     245           0 :     tctx->error = sysdb_transaction_commit(tctx->sysdb);
     246           0 :     if (tctx->error) {
     247           0 :         PyErr_SetSssError(tctx->error);
     248           0 :         goto fail;
     249             :     }
     250           0 :     in_transaction = false;
     251             : 
     252             :     /* Create user's home directory and/or mail spool */
     253           0 :     if (tctx->octx->create_homedir) {
     254             :         /* We need to know the UID and GID of the user, if
     255             :          * sysdb did assign it automatically, do a lookup */
     256           0 :         if (tctx->octx->uid == 0 || tctx->octx->gid == 0) {
     257           0 :             ret = sysdb_getpwnam_sync(tctx,
     258           0 :                                       tctx->octx->name,
     259             :                                       tctx->octx);
     260           0 :             if (ret != EOK) {
     261           0 :                 PyErr_SetSssError(ret);
     262           0 :                 goto fail;
     263             :             }
     264             :         }
     265             : 
     266           0 :         ret = create_homedir(tctx->octx->skeldir,
     267           0 :                              tctx->octx->home,
     268           0 :                              tctx->octx->uid,
     269           0 :                              tctx->octx->gid,
     270           0 :                              tctx->octx->umask);
     271           0 :         if (ret != EOK) {
     272           0 :             PyErr_SetSssError(ret);
     273           0 :             goto fail;
     274             :         }
     275             : 
     276             :         /* failure here should not be fatal */
     277           0 :         create_mail_spool(tctx,
     278           0 :                           tctx->octx->name,
     279           0 :                           tctx->octx->maildir,
     280           0 :                           tctx->octx->uid,
     281           0 :                           tctx->octx->gid);
     282             :     }
     283             : 
     284           0 :     talloc_zfree(tctx);
     285           0 :     Py_RETURN_NONE;
     286             : 
     287             : fail:
     288           0 :     if (in_transaction) {
     289             :         /* We do not handle return value of sysdb_transaction_cancel()
     290             :          * because we don't want to overwrite previous error code.
     291             :          */
     292           0 :         sysdb_transaction_cancel(tctx->sysdb);
     293             :     }
     294           0 :     talloc_zfree(tctx);
     295           0 :     return NULL;
     296             : }
     297             : 
     298             : /*
     299             :  * Delete a user
     300             :  */
     301             : PyDoc_STRVAR(py_sss_userdel__doc__,
     302             :     "Remove the user named ``username``.\n\n"
     303             :     ":param username: Name of user being removed\n"
     304             :     ":param kwargs: Keyword arguments that customize the operation\n\n"
     305             :     "* userdel can be customized further with keyword arguments:\n"
     306             :     "    * ``force``: (bool) Force removal of files not owned by the user\n"
     307             :     "    * ``remove``: (bool) Toggle removing home directory and mail spool\n");
     308             : 
     309           0 : static PyObject *py_sss_userdel(PySssLocalObject *self,
     310             :                                 PyObject *args,
     311             :                                 PyObject *kwds)
     312             : {
     313           0 :     struct tools_ctx *tctx = NULL;
     314           0 :     char *username = NULL;
     315             :     int ret;
     316           0 :     PyObject *py_remove = Py_None;
     317           0 :     int remove_home = 0;
     318           0 :     PyObject *py_force = Py_None;
     319           0 :     const char * const kwlist[] = { "username", "remove", "force", NULL };
     320             : 
     321           0 :     if(!PyArg_ParseTupleAndKeywords(args, kwds,
     322             :                                     discard_const_p(char, "s|O!O!"),
     323             :                                     discard_const_p(char *, kwlist),
     324             :                                     &username,
     325             :                                     &PyBool_Type,
     326             :                                     &py_remove,
     327             :                                     &PyBool_Type,
     328             :                                     &py_force)) {
     329           0 :         goto fail;
     330             :     }
     331             : 
     332           0 :     tctx = init_ctx(self);
     333           0 :     if (!tctx) {
     334           0 :         PyErr_NoMemory();
     335           0 :         return NULL;
     336             :     }
     337             : 
     338           0 :     tctx->octx->name = username;
     339             : 
     340           0 :     if (py_remove == Py_True) {
     341           0 :         remove_home = DO_REMOVE_HOME;
     342           0 :     } else if (py_remove == Py_False) {
     343           0 :         remove_home = DO_NOT_REMOVE_HOME;
     344             :     }
     345             : 
     346             :     /*
     347             :      * Fills in defaults for ops_ctx user did not specify.
     348             :      */
     349           0 :     ret = userdel_defaults(tctx,
     350             :                            tctx->confdb,
     351             :                            tctx->octx,
     352             :                            remove_home);
     353           0 :     if (ret != EOK) {
     354           0 :         PyErr_SetSssError(ret);
     355           0 :         goto fail;
     356             :     }
     357             : 
     358           0 :     ret = run_userdel_cmd(tctx);
     359           0 :     if (ret != EOK) {
     360           0 :         PyErr_SetSssError(ret);
     361           0 :         goto fail;
     362             :     }
     363             : 
     364           0 :     if (tctx->octx->remove_homedir) {
     365           0 :         ret = sysdb_getpwnam_sync(tctx,
     366           0 :                                   tctx->octx->name,
     367             :                                   tctx->octx);
     368           0 :         if (ret != EOK) {
     369           0 :             PyErr_SetSssError(ret);
     370           0 :             goto fail;
     371             :         }
     372             :     }
     373             : 
     374             :     /* Delete the user */
     375           0 :     ret = userdel(tctx, self->sysdb, tctx->octx);
     376           0 :     if (ret != EOK) {
     377           0 :         PyErr_SetSssError(ret);
     378           0 :         goto fail;
     379             :     }
     380             : 
     381           0 :     if (tctx->octx->remove_homedir) {
     382           0 :         ret = remove_homedir(tctx,
     383           0 :                              tctx->octx->home,
     384           0 :                              tctx->octx->maildir,
     385           0 :                              tctx->octx->name,
     386           0 :                              tctx->octx->uid,
     387             :                              (py_force == Py_True));
     388           0 :         if (ret != EOK) {
     389           0 :             PyErr_SetSssError(ret);
     390           0 :             goto fail;
     391             :         }
     392             :     }
     393             : 
     394           0 :     talloc_zfree(tctx);
     395           0 :     Py_RETURN_NONE;
     396             : 
     397             : fail:
     398           0 :     talloc_zfree(tctx);
     399           0 :     return NULL;
     400             : }
     401             : 
     402             : /*
     403             :  * Modify a user
     404             :  */
     405             : PyDoc_STRVAR(py_sss_usermod__doc__,
     406             :     "Modify a user.\n\n"
     407             :     ":param username: Name of user being modified\n\n"
     408             :     ":param kwargs: Keyword arguments that customize the operation\n\n"
     409             :     "* usermod can be customized further with keyword arguments:\n"
     410             :     "    * ``uid``: The UID of the user\n"
     411             :     "    * ``gid``: The GID of the user\n"
     412             :     "    * ``gecos``: The comment string\n"
     413             :     "    * ``homedir``: Home directory\n"
     414             :     "    * ``shell``: Login shell\n"
     415             :     "    * ``addgroups``: List of groups to add the user to\n"
     416             :     "    * ``rmgroups``: List of groups to remove the user from\n"
     417             :     "    * ``lock``: Lock or unlock the account\n");
     418             : 
     419           0 : static PyObject *py_sss_usermod(PySssLocalObject *self,
     420             :                                 PyObject *args,
     421             :                                 PyObject *kwds)
     422             : {
     423           0 :     struct tools_ctx *tctx = NULL;
     424           0 :     PyObject *py_addgroups = Py_None;
     425           0 :     PyObject *py_rmgroups = Py_None;
     426           0 :     unsigned long uid = 0;
     427           0 :     unsigned long gid = 0;
     428           0 :     char *gecos = NULL;
     429           0 :     char *home = NULL;
     430           0 :     char *shell = NULL;
     431           0 :     char *username = NULL;
     432           0 :     unsigned long lock = 0;
     433           0 :     const char * const kwlist[] = { "username", "uid", "gid", "lock",
     434             :                                     "gecos",  "homedir", "shell",
     435             :                                     "addgroups", "rmgroups", NULL };
     436           0 :     bool in_transaction = false;
     437             : 
     438             :     /* parse arguments */
     439           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
     440             :                                      discard_const_p(char, "s|kkksssO!O!"),
     441             :                                      discard_const_p(char *, kwlist),
     442             :                                      &username,
     443             :                                      &uid,
     444             :                                      &gid,
     445             :                                      &lock,
     446             :                                      &gecos,
     447             :                                      &home,
     448             :                                      &shell,
     449             :                                      &PyList_Type,
     450             :                                      &py_addgroups,
     451             :                                      &PyList_Type,
     452             :                                      &py_rmgroups)) {
     453           0 :         goto fail;
     454             :     }
     455             : 
     456           0 :     tctx = init_ctx(self);
     457           0 :     if (!tctx) {
     458           0 :         PyErr_NoMemory();
     459           0 :         return NULL;
     460             :     }
     461             : 
     462           0 :     if (lock && lock != DO_LOCK && lock != DO_UNLOCK) {
     463           0 :         PyErr_SetString(PyExc_ValueError,
     464             :                         "Unkown value for lock parameter");
     465           0 :         goto fail;
     466             :     }
     467             : 
     468           0 :     if (py_addgroups != Py_None) {
     469           0 :         tctx->octx->addgroups = PyList_AsStringList(tctx,
     470             :                                                     py_addgroups,
     471             :                                                     "addgroups");
     472           0 :         if (!tctx->octx->addgroups) {
     473           0 :             return NULL;
     474             :         }
     475             :     }
     476             : 
     477           0 :     if (py_rmgroups != Py_None) {
     478           0 :         tctx->octx->rmgroups = PyList_AsStringList(tctx,
     479             :                                                    py_rmgroups,
     480             :                                                    "rmgroups");
     481           0 :         if (!tctx->octx->rmgroups) {
     482           0 :             return NULL;
     483             :         }
     484             :     }
     485             : 
     486           0 :     tctx->octx->name  = username;
     487           0 :     tctx->octx->uid   = uid;
     488           0 :     tctx->octx->gid   = gid;
     489           0 :     tctx->octx->gecos = gecos;
     490           0 :     tctx->octx->home  = home;
     491           0 :     tctx->octx->shell = shell;
     492           0 :     tctx->octx->lock  = lock;
     493             : 
     494             :     /* Modify the user within a transaction */
     495           0 :     tctx->error = sysdb_transaction_start(tctx->sysdb);
     496           0 :     if (tctx->error != EOK) {
     497           0 :         PyErr_SetSssError(tctx->error);
     498           0 :         goto fail;
     499             :     }
     500           0 :     in_transaction = true;
     501             : 
     502             :     /* usermod */
     503           0 :     tctx->error = usermod(tctx, tctx->octx);
     504           0 :     if (tctx->error) {
     505           0 :         PyErr_SetSssError(tctx->error);
     506           0 :         goto fail;
     507             :     }
     508             : 
     509           0 :     tctx->error = sysdb_transaction_commit(tctx->sysdb);
     510           0 :     if (tctx->error) {
     511           0 :         PyErr_SetSssError(tctx->error);
     512           0 :         goto fail;
     513             :     }
     514           0 :     in_transaction = false;
     515             : 
     516           0 :     talloc_zfree(tctx);
     517           0 :     Py_RETURN_NONE;
     518             : 
     519             : fail:
     520           0 :     if (in_transaction) {
     521             :         /* We do not handle return value of sysdb_transaction_cancel()
     522             :          * because we don't want to overwrite previous error code.
     523             :          */
     524           0 :         sysdb_transaction_cancel(tctx->sysdb);
     525             :     }
     526           0 :     talloc_zfree(tctx);
     527           0 :     return NULL;
     528             : }
     529             : 
     530             : /*
     531             :  * Add a group
     532             :  */
     533             : PyDoc_STRVAR(py_sss_groupadd__doc__,
     534             :     "Add a group.\n\n"
     535             :     ":param groupname: Name of group being added\n\n"
     536             :     ":param kwargs: Keyword arguments ro customize the operation\n\n"
     537             :     "* groupmod can be customized further with keyword arguments:\n"
     538             :     "   * ``gid``: The GID of the group\n");
     539             : 
     540           0 : static PyObject *py_sss_groupadd(PySssLocalObject *self,
     541             :                                  PyObject *args,
     542             :                                  PyObject *kwds)
     543             : {
     544           0 :     struct tools_ctx *tctx = NULL;
     545             :     char *groupname;
     546           0 :     unsigned long gid = 0;
     547           0 :     const char * const kwlist[] = { "groupname", "gid", NULL };
     548           0 :     bool in_transaction = false;
     549             : 
     550             :     /* parse arguments */
     551           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
     552             :                                      discard_const_p(char, "s|k"),
     553             :                                      discard_const_p(char *, kwlist),
     554             :                                      &groupname,
     555             :                                      &gid)) {
     556           0 :         goto fail;
     557             :     }
     558             : 
     559           0 :     tctx = init_ctx(self);
     560           0 :     if (!tctx) {
     561           0 :         PyErr_NoMemory();
     562           0 :         return NULL;
     563             :     }
     564             : 
     565           0 :     tctx->octx->name = groupname;
     566           0 :     tctx->octx->gid = gid;
     567             : 
     568             :     /* Add the group within a transaction */
     569           0 :     tctx->error = sysdb_transaction_start(tctx->sysdb);
     570           0 :     if (tctx->error != EOK) {
     571           0 :         PyErr_SetSssError(tctx->error);
     572           0 :         goto fail;
     573             :     }
     574           0 :     in_transaction = true;
     575             : 
     576             :     /* groupadd */
     577           0 :     tctx->error = groupadd(tctx->octx);
     578           0 :     if (tctx->error) {
     579           0 :         PyErr_SetSssError(tctx->error);
     580           0 :         goto fail;
     581             :     }
     582             : 
     583           0 :     tctx->error = sysdb_transaction_commit(tctx->sysdb);
     584           0 :     if (tctx->error) {
     585           0 :         PyErr_SetSssError(tctx->error);
     586           0 :         goto fail;
     587             :     }
     588           0 :     in_transaction = false;
     589             : 
     590           0 :     talloc_zfree(tctx);
     591           0 :     Py_RETURN_NONE;
     592             : 
     593             : fail:
     594           0 :     if (in_transaction) {
     595             :         /* We do not handle return value of sysdb_transaction_cancel()
     596             :          * because we don't want to overwrite previous error code.
     597             :          */
     598           0 :         sysdb_transaction_cancel(tctx->sysdb);
     599             :     }
     600           0 :     talloc_zfree(tctx);
     601           0 :     return NULL;
     602             : }
     603             : 
     604             : /*
     605             :  * Delete a group
     606             :  */
     607             : PyDoc_STRVAR(py_sss_groupdel__doc__,
     608             :     "Remove a group.\n\n"
     609             :     ":param groupname: Name of group being removed\n");
     610             : 
     611           0 : static PyObject *py_sss_groupdel(PySssLocalObject *self,
     612             :                                 PyObject *args,
     613             :                                 PyObject *kwds)
     614             : {
     615           0 :     struct tools_ctx *tctx = NULL;
     616           0 :     char *groupname = NULL;
     617             :     int ret;
     618             : 
     619           0 :     if(!PyArg_ParseTuple(args, discard_const_p(char, "s"), &groupname)) {
     620           0 :         goto fail;
     621             :     }
     622             : 
     623           0 :     tctx = init_ctx(self);
     624           0 :     if (!tctx) {
     625           0 :         PyErr_NoMemory();
     626           0 :         return NULL;
     627             :     }
     628             : 
     629           0 :     tctx->octx->name = groupname;
     630             : 
     631             :     /* Remove the group */
     632           0 :     ret = groupdel(tctx, self->sysdb, tctx->octx);
     633           0 :     if (ret != EOK) {
     634           0 :         PyErr_SetSssError(ret);
     635           0 :         goto fail;
     636             :     }
     637             : 
     638           0 :     talloc_zfree(tctx);
     639           0 :     Py_RETURN_NONE;
     640             : 
     641             : fail:
     642           0 :     talloc_zfree(tctx);
     643           0 :     return NULL;
     644             : }
     645             : 
     646             : /*
     647             :  * Modify a group
     648             :  */
     649             : PyDoc_STRVAR(py_sss_groupmod__doc__,
     650             : "Modify a group.\n\n"
     651             : ":param groupname: Name of group being modified\n\n"
     652             : ":param kwargs: Keyword arguments ro customize the operation\n\n"
     653             : "* groupmod can be customized further with keyword arguments:\n"
     654             : "   * ``gid``: The GID of the group\n\n"
     655             : "   * ``addgroups``: Groups to add the group to\n\n"
     656             : "   * ``rmgroups``: Groups to remove the group from\n\n");
     657             : 
     658           0 : static PyObject *py_sss_groupmod(PySssLocalObject *self,
     659             :                                 PyObject *args,
     660             :                                 PyObject *kwds)
     661             : {
     662           0 :     struct tools_ctx *tctx = NULL;
     663           0 :     PyObject *py_addgroups = Py_None;
     664           0 :     PyObject *py_rmgroups = Py_None;
     665           0 :     unsigned long gid = 0;
     666           0 :     char *groupname = NULL;
     667           0 :     const char * const kwlist[] = { "groupname", "gid", "addgroups",
     668             :                                     "rmgroups", NULL };
     669           0 :     bool in_transaction = false;
     670             : 
     671             :     /* parse arguments */
     672           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds,
     673             :                                      discard_const_p(char, "s|kO!O!"),
     674             :                                      discard_const_p(char *, kwlist),
     675             :                                      &groupname,
     676             :                                      &gid,
     677             :                                      &PyList_Type,
     678             :                                      &py_addgroups,
     679             :                                      &PyList_Type,
     680             :                                      &py_rmgroups)) {
     681           0 :         goto fail;
     682             :     }
     683             : 
     684           0 :     tctx = init_ctx(self);
     685           0 :     if (!tctx) {
     686           0 :         PyErr_NoMemory();
     687           0 :         return NULL;
     688             :     }
     689             : 
     690           0 :     if (py_addgroups != Py_None) {
     691           0 :         tctx->octx->addgroups = PyList_AsStringList(tctx,
     692             :                                              py_addgroups,
     693             :                                              "addgroups");
     694           0 :         if (!tctx->octx->addgroups) {
     695           0 :             return NULL;
     696             :         }
     697             :     }
     698             : 
     699           0 :     if (py_rmgroups != Py_None) {
     700           0 :         tctx->octx->rmgroups = PyList_AsStringList(tctx,
     701             :                                             py_rmgroups,
     702             :                                             "rmgroups");
     703           0 :         if (!tctx->octx->rmgroups) {
     704           0 :             return NULL;
     705             :         }
     706             :     }
     707             : 
     708           0 :     tctx->octx->name = groupname;
     709           0 :     tctx->octx->gid = gid;
     710             : 
     711             :     /* Modify the group within a transaction */
     712           0 :     tctx->error = sysdb_transaction_start(tctx->sysdb);
     713           0 :     if (tctx->error != EOK) {
     714           0 :         PyErr_SetSssError(tctx->error);
     715           0 :         goto fail;
     716             :     }
     717           0 :     in_transaction = true;
     718             : 
     719             :     /* groupmod */
     720           0 :     tctx->error = groupmod(tctx, tctx->octx);
     721           0 :     if (tctx->error) {
     722           0 :         PyErr_SetSssError(tctx->error);
     723           0 :         goto fail;
     724             :     }
     725             : 
     726           0 :     tctx->error = sysdb_transaction_commit(tctx->sysdb);
     727           0 :     if (tctx->error) {
     728           0 :         PyErr_SetSssError(tctx->error);
     729           0 :         goto fail;
     730             :     }
     731           0 :     in_transaction = false;
     732             : 
     733           0 :     talloc_zfree(tctx);
     734           0 :     Py_RETURN_NONE;
     735             : 
     736             : fail:
     737           0 :     if (in_transaction) {
     738             :         /* We do not handle return value of sysdb_transaction_cancel()
     739             :          * because we don't want to overwrite previous error code.
     740             :          */
     741           0 :         sysdb_transaction_cancel(tctx->sysdb);
     742             :     }
     743           0 :     talloc_zfree(tctx);
     744           0 :     return NULL;
     745             : }
     746             : 
     747             : /*
     748             :  * Get list of groups user belongs to
     749             :  */
     750             : PyDoc_STRVAR(py_sss_getgrouplist__doc__,
     751             :     "Get list of groups user belongs to.\n\n"
     752             :     "NOTE: The interface uses the system NSS calls and is not limited to "
     753             :     "users served by the SSSD!\n"
     754             :     ":param username: name of user to get list for\n");
     755             : 
     756           0 : static PyObject *py_sss_getgrouplist(PyObject *self, PyObject *args)
     757             : {
     758           0 :     char *username = NULL;
     759           0 :     gid_t *groups = NULL;
     760             :     struct passwd *pw;
     761             :     struct group *gr;
     762             :     int ngroups;
     763             :     int ret;
     764             :     Py_ssize_t i, idx;
     765             :     PyObject *groups_tuple;
     766             : 
     767           0 :     if(!PyArg_ParseTuple(args, discard_const_p(char, "s"), &username)) {
     768           0 :         goto fail;
     769             :     }
     770             : 
     771           0 :     pw = getpwnam(username);
     772           0 :     if (pw == NULL) {
     773           0 :         goto fail;
     774             :     }
     775             : 
     776           0 :     ngroups = 32;
     777           0 :     groups = malloc(sizeof(gid_t) * ngroups);
     778           0 :     if (groups == NULL) {
     779           0 :         goto fail;
     780             :     }
     781             : 
     782             :     do {
     783           0 :         ret = getgrouplist(username, pw->pw_gid, groups, &ngroups);
     784           0 :         if (ret < ngroups) {
     785           0 :             gid_t *tmp_groups = realloc(groups, ngroups * sizeof(gid_t));
     786           0 :             if (tmp_groups == NULL) {
     787           0 :                 goto fail;
     788             :             }
     789           0 :             groups = tmp_groups;
     790             :         }
     791           0 :     } while (ret != ngroups);
     792             : 
     793           0 :     groups_tuple = PyTuple_New((Py_ssize_t) ngroups);
     794           0 :     if (groups_tuple == NULL) {
     795           0 :         goto fail;
     796             :     }
     797             : 
     798             :     /* Populate a tuple with names of groups
     799             :      * In unlikely case of group not being able to resolve, skip it
     800             :      * We also need to resize resulting tuple to avoid empty elements there */
     801           0 :     idx = 0;
     802           0 :     for (i = 0; i < ngroups; i++) {
     803           0 :         gr = getgrgid(groups[i]);
     804           0 :         if (gr) {
     805           0 :             PyTuple_SetItem(groups_tuple, idx,
     806             : #ifdef IS_PY3K
     807           0 :                     PyUnicode_FromString(gr->gr_name)
     808             : #else
     809           0 :                     PyString_FromString(gr->gr_name)
     810             : #endif
     811             :                     );
     812           0 :             idx++;
     813             :         }
     814             :     }
     815           0 :     free(groups);
     816           0 :     groups = NULL;
     817             : 
     818           0 :     if (i != idx) {
     819           0 :         _PyTuple_Resize(&groups_tuple, idx);
     820             :     }
     821             : 
     822           0 :     return groups_tuple;
     823             : 
     824             : fail:
     825           0 :     free(groups);
     826           0 :     return NULL;
     827             : }
     828             : 
     829             : /*** python plumbing begins here ***/
     830             : 
     831             : /*
     832             :  * The sss.local destructor
     833             :  */
     834           0 : static void PySssLocalObject_dealloc(PySssLocalObject *self)
     835             : {
     836           0 :     talloc_free(self->mem_ctx);
     837           0 :     Py_TYPE(self)->tp_free((PyObject *)self);
     838           0 : }
     839             : 
     840             : /*
     841             :  * The sss.local constructor
     842             :  */
     843           0 : static PyObject *PySssLocalObject_new(PyTypeObject *type,
     844             :                                       PyObject *args,
     845             :                                       PyObject *kwds)
     846             : {
     847             :     TALLOC_CTX *mem_ctx;
     848             :     PySssLocalObject *self;
     849             :     char *confdb_path;
     850             :     int ret;
     851             : 
     852           0 :     mem_ctx = talloc_new(NULL);
     853           0 :     if (mem_ctx == NULL) {
     854           0 :         PyErr_NoMemory();
     855           0 :         return NULL;
     856             :     }
     857             : 
     858           0 :     self = (PySssLocalObject *) type->tp_alloc(type, 0);
     859           0 :     if (self == NULL) {
     860           0 :         talloc_free(mem_ctx);
     861           0 :         PyErr_NoMemory();
     862           0 :         return NULL;
     863             :     }
     864           0 :     self->mem_ctx = mem_ctx;
     865             : 
     866           0 :     confdb_path = talloc_asprintf(self->mem_ctx, "%s/%s", DB_PATH, CONFDB_FILE);
     867           0 :     if (confdb_path == NULL) {
     868           0 :         PyErr_NoMemory();
     869           0 :         goto fail;
     870             :     }
     871             : 
     872             :     /* Connect to the conf db */
     873           0 :     ret = confdb_init(self->mem_ctx, &self->confdb, confdb_path);
     874           0 :     if (ret != EOK) {
     875           0 :         PyErr_SetSssErrorWithMessage(ret,
     876             :                 "Could not initialize connection to the confdb\n");
     877           0 :         goto fail;
     878             :     }
     879             : 
     880           0 :     ret = sssd_domain_init(self->mem_ctx, self->confdb, "local",
     881             :                            DB_PATH, &self->local);
     882           0 :     if (ret != EOK) {
     883           0 :         PyErr_SetSssErrorWithMessage(ret,
     884             :                 "Could not initialize connection to the sysdb\n");
     885           0 :         goto fail;
     886             :     }
     887           0 :     self->sysdb = self->local->sysdb;
     888             : 
     889           0 :     self->lock = DO_LOCK;
     890           0 :     self->unlock = DO_UNLOCK;
     891             : 
     892           0 :     return (PyObject *) self;
     893             : 
     894             : fail:
     895           0 :     Py_DECREF(self);
     896           0 :     return NULL;
     897             : }
     898             : 
     899             : /*
     900             :  * sss.local object methods
     901             :  */
     902             : static PyMethodDef sss_local_methods[] = {
     903             :     { sss_py_const_p(char, "useradd"), (PyCFunction) py_sss_useradd,
     904             :       METH_KEYWORDS, py_sss_useradd__doc__
     905             :     },
     906             :     { sss_py_const_p(char, "userdel"), (PyCFunction) py_sss_userdel,
     907             :       METH_KEYWORDS, py_sss_userdel__doc__
     908             :     },
     909             :     { sss_py_const_p(char, "usermod"), (PyCFunction) py_sss_usermod,
     910             :       METH_KEYWORDS, py_sss_usermod__doc__
     911             :     },
     912             :     { sss_py_const_p(char, "groupadd"), (PyCFunction) py_sss_groupadd,
     913             :       METH_KEYWORDS, py_sss_groupadd__doc__
     914             :     },
     915             :     { sss_py_const_p(char, "groupdel"), (PyCFunction) py_sss_groupdel,
     916             :       METH_KEYWORDS, py_sss_groupdel__doc__
     917             :     },
     918             :     { sss_py_const_p(char, "groupmod"), (PyCFunction) py_sss_groupmod,
     919             :       METH_KEYWORDS, py_sss_groupmod__doc__
     920             :     },
     921             :     {NULL, NULL, 0, NULL}        /* Sentinel */
     922             : };
     923             : 
     924             : static PyMemberDef sss_local_members[] = {
     925             :     { discard_const_p(char, "lock"), T_INT,
     926             :       offsetof(PySssLocalObject, lock), READONLY, NULL},
     927             :     { discard_const_p(char, "unlock"), T_INT,
     928             :       offsetof(PySssLocalObject, unlock), READONLY, NULL},
     929             :     {NULL, 0, 0, 0, NULL} /* Sentinel */
     930             : };
     931             : 
     932             : /*
     933             :  * sss.local object properties
     934             :  */
     935             : static PyTypeObject pysss_local_type = {
     936             :     PyVarObject_HEAD_INIT(NULL, 0)
     937             :     .tp_name = sss_py_const_p(char, "sss.local"),
     938             :     .tp_basicsize = sizeof(PySssLocalObject),
     939             :     .tp_new = PySssLocalObject_new,
     940             :     .tp_dealloc = (destructor) PySssLocalObject_dealloc,
     941             :     .tp_methods = sss_local_methods,
     942             :     .tp_members = sss_local_members,
     943             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
     944             :     .tp_doc   = sss_py_const_p(char, "SSS DB manipulation"),
     945             : };
     946             : 
     947             : /* ==================== obfuscation python wrappers ========================*/
     948             : 
     949             : /*
     950             :  * The sss.local object
     951             :  */
     952             : typedef struct {
     953             :     PyObject_HEAD
     954             : 
     955             :     int aes_256;
     956             : } PySssPasswordObject;
     957             : 
     958             : PyDoc_STRVAR(py_sss_encrypt__doc__,
     959             : "Obfuscate a password\n\n"
     960             : ":param password: The password to obfuscate\n\n"
     961             : ":param method: The obfuscation method\n\n");
     962             : 
     963           0 : static PyObject *py_sss_encrypt(PySssPasswordObject *self,
     964             :                                 PyObject *args,
     965             :                                 PyObject *kwds)
     966             : {
     967           0 :     char *password = NULL;
     968             :     int plen; /* may contain NULL bytes */
     969           0 :     char *obfpwd = NULL;
     970           0 :     TALLOC_CTX *tctx = NULL;
     971             :     int ret;
     972             :     int mode;
     973           0 :     PyObject *retval = NULL;
     974             : 
     975             :     /* parse arguments */
     976           0 :     if (!PyArg_ParseTuple(args, discard_const_p(char, "s#i"),
     977             :                           &password, &plen, &mode)) {
     978           0 :         return NULL;
     979             :     }
     980             : 
     981           0 :     tctx = talloc_new(NULL);
     982           0 :     if (!tctx) {
     983           0 :         PyErr_NoMemory();
     984           0 :         return NULL;
     985             :     }
     986             : 
     987           0 :     ret = sss_password_encrypt(tctx, password, plen+1,
     988             :                                mode, &obfpwd);
     989           0 :     if (ret != EOK) {
     990           0 :         PyErr_SetSssError(ret);
     991           0 :         goto fail;
     992             :     }
     993             : 
     994           0 :     retval = Py_BuildValue(sss_py_const_p(char, "s"), obfpwd);
     995           0 :     if (retval == NULL) {
     996           0 :         goto fail;
     997             :     }
     998             : 
     999             : fail:
    1000           0 :     talloc_zfree(tctx);
    1001           0 :     return retval;
    1002             : }
    1003             : 
    1004             : #if 0
    1005             : PyDoc_STRVAR(py_sss_decrypt__doc__,
    1006             : "Deobfuscate a password\n\n"
    1007             : ":param obfpwd: The password to convert back to clear text\n\n");
    1008             : 
    1009             : static PyObject *py_sss_decrypt(PySssPasswordObject *self,
    1010             :                                 PyObject *args,
    1011             :                                 PyObject *kwds)
    1012             : {
    1013             :     char *password = NULL;
    1014             :     char *obfpwd = NULL;
    1015             :     TALLOC_CTX *tctx = NULL;
    1016             :     int ret;
    1017             :     PyObject *retval = NULL;
    1018             : 
    1019             :     /* parse arguments */
    1020             :     if (!PyArg_ParseTuple(args, discard_const_p(char, "s"),
    1021             :                           &obfpwd)) {
    1022             :         return NULL;
    1023             :     }
    1024             : 
    1025             :     tctx = talloc_new(NULL);
    1026             :     if (!tctx) {
    1027             :         PyErr_NoMemory();
    1028             :         return NULL;
    1029             :     }
    1030             : 
    1031             :     ret = sss_password_decrypt(tctx, obfpwd, &password);
    1032             :     if (ret != EOK) {
    1033             :         PyErr_SetSssError(ret);
    1034             :         goto fail;
    1035             :     }
    1036             : 
    1037             :     retval = Py_BuildValue("s", password);
    1038             :     if (retval == NULL) {
    1039             :         goto fail;
    1040             :     }
    1041             : 
    1042             : fail:
    1043             :     talloc_zfree(tctx);
    1044             :     return retval;
    1045             : }
    1046             : #endif
    1047             : 
    1048             : /*
    1049             :  * The sss.password destructor
    1050             :  */
    1051           0 : static void PySssPasswordObject_dealloc(PySssPasswordObject *self)
    1052             : {
    1053           0 :     Py_TYPE(self)->tp_free((PyObject*) self);
    1054           0 : }
    1055             : 
    1056             : /*
    1057             :  * The sss.password constructor
    1058             :  */
    1059           0 : static PyObject *PySssPasswordObject_new(PyTypeObject *type,
    1060             :                                          PyObject *args,
    1061             :                                          PyObject *kwds)
    1062             : {
    1063             :     PySssPasswordObject *self;
    1064             : 
    1065           0 :     self = (PySssPasswordObject *) type->tp_alloc(type, 0);
    1066           0 :     if (self == NULL) {
    1067           0 :         PyErr_NoMemory();
    1068           0 :         return NULL;
    1069             :     }
    1070             : 
    1071           0 :     self->aes_256 = AES_256;
    1072             : 
    1073           0 :     return (PyObject *) self;
    1074             : }
    1075             : 
    1076             : /*
    1077             :  * sss.password object methods
    1078             :  */
    1079             : static PyMethodDef sss_password_methods[] = {
    1080             :     { sss_py_const_p(char, "encrypt"), (PyCFunction) py_sss_encrypt,
    1081             :       METH_VARARGS | METH_STATIC, py_sss_encrypt__doc__
    1082             :     },
    1083             : #if 0
    1084             :     { "decrypt", (PyCFunction) py_sss_decrypt,
    1085             :       METH_VARARGS | METH_STATIC, py_sss_decrypt__doc__
    1086             :     },
    1087             : #endif
    1088             :     {NULL, NULL, 0, NULL}        /* Sentinel */
    1089             : };
    1090             : 
    1091             : /*
    1092             :  * sss.password object members
    1093             :  */
    1094             : static PyMemberDef sss_password_members[] = {
    1095             :     { discard_const_p(char, "AES_256"), T_INT,
    1096             :       offsetof(PySssPasswordObject, aes_256), READONLY, NULL},
    1097             :     {NULL, 0, 0, 0, NULL} /* Sentinel */
    1098             : };
    1099             : 
    1100             : /*
    1101             :  * sss.password object properties
    1102             :  */
    1103             : static PyTypeObject pysss_password_type = {
    1104             :     PyVarObject_HEAD_INIT(NULL, 0)
    1105             :     .tp_name = sss_py_const_p(char, "sss.password"),
    1106             :     .tp_basicsize = sizeof(PySssPasswordObject),
    1107             :     .tp_new = PySssPasswordObject_new,
    1108             :     .tp_dealloc = (destructor) PySssPasswordObject_dealloc,
    1109             :     .tp_methods = sss_password_methods,
    1110             :     .tp_members = sss_password_members,
    1111             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    1112             :     .tp_doc   = sss_py_const_p(char, "SSS password obfuscation"),
    1113             : };
    1114             : 
    1115             : /* ==================== the sss module initialization =======================*/
    1116             : 
    1117             : /*
    1118             :  * Module methods
    1119             :  */
    1120             : static PyMethodDef module_methods[] = {
    1121             :         {"getgrouplist", py_sss_getgrouplist, METH_VARARGS, py_sss_getgrouplist__doc__},
    1122             :         {NULL, NULL, 0, NULL}  /* Sentinel */
    1123             : };
    1124             : 
    1125             : /*
    1126             :  * Module initialization
    1127             :  */
    1128             : #ifdef IS_PY3K
    1129             : static struct PyModuleDef pysssdef = {
    1130             :     PyModuleDef_HEAD_INIT,
    1131             :     "pysss",
    1132             :     NULL,
    1133             :     -1,
    1134             :     module_methods,
    1135             :     NULL,
    1136             :     NULL,
    1137             :     NULL,
    1138             :     NULL
    1139             : };
    1140             : 
    1141             : PyMODINIT_FUNC
    1142           0 : PyInit_pysss(void)
    1143             : #else
    1144             : PyMODINIT_FUNC
    1145           0 : initpysss(void)
    1146             : #endif
    1147             : {
    1148             :     PyObject *m;
    1149             : 
    1150           0 :     if (PyType_Ready(&pysss_local_type) < 0)
    1151           0 :         MODINITERROR;
    1152           0 :     if (PyType_Ready(&pysss_password_type) < 0)
    1153           0 :         MODINITERROR;
    1154             : 
    1155             : #ifdef IS_PY3K
    1156           0 :     m = PyModule_Create(&pysssdef);
    1157             : #else
    1158           0 :     m = Py_InitModule(discard_const_p(char, "pysss"), module_methods);
    1159             : #endif
    1160           0 :     if (m == NULL)
    1161           0 :         MODINITERROR;
    1162             : 
    1163           0 :     Py_INCREF(&pysss_local_type);
    1164           0 :     PyModule_AddObject(m, discard_const_p(char, "local"), (PyObject *)&pysss_local_type);
    1165           0 :     Py_INCREF(&pysss_password_type);
    1166           0 :     PyModule_AddObject(m, discard_const_p(char, "password"), (PyObject *)&pysss_password_type);
    1167             : 
    1168             : #ifdef IS_PY3K
    1169           0 :     return m;
    1170             : #endif
    1171             : }
    1172             : 

Generated by: LCOV version 1.10