summaryrefslogtreecommitdiffstats
path: root/src/python
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2010-02-18 07:49:04 -0500
committerStephen Gallagher <sgallagh@redhat.com>2010-02-18 13:48:45 -0500
commit1c48b5a62f73234ed26bb20f0ab345ab61cda0ab (patch)
tree0b6cddd567a862e1a7b5df23764869782a62ca78 /src/python
parent8c56df3176f528fe0260974b3bf934173c4651ea (diff)
downloadsssd-1c48b5a62f73234ed26bb20f0ab345ab61cda0ab.tar.gz
sssd-1c48b5a62f73234ed26bb20f0ab345ab61cda0ab.tar.xz
sssd-1c48b5a62f73234ed26bb20f0ab345ab61cda0ab.zip
Rename server/ directory to src/
Also update BUILD.txt
Diffstat (limited to 'src/python')
-rw-r--r--src/python/pysss.c937
1 files changed, 937 insertions, 0 deletions
diff --git a/src/python/pysss.c b/src/python/pysss.c
new file mode 100644
index 000000000..8011ed67e
--- /dev/null
+++ b/src/python/pysss.c
@@ -0,0 +1,937 @@
+/*
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2009 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+#include <structmember.h>
+#include <talloc.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "util/util.h"
+#include "db/sysdb.h"
+#include "tools/tools_util.h"
+#include "tools/sss_sync_ops.h"
+
+#define TRANSACTION_WAIT(trs, retval) do { \
+ while (!trs->transaction_done) { \
+ tevent_loop_once(trs->self->ev); \
+ } \
+ retval = trs->error; \
+ if (retval) { \
+ PyErr_SetSssError(retval); \
+ goto fail; \
+ } \
+} while(0)
+
+/*
+ * function taken from samba sources tree as of Aug 20 2009,
+ * file source4/lib/ldb/pyldb.c
+ */
+static char **PyList_AsStringList(TALLOC_CTX *mem_ctx, PyObject *list,
+ const char *paramname)
+{
+ char **ret;
+ int i;
+
+ ret = talloc_array(NULL, char *, PyList_Size(list)+1);
+ for (i = 0; i < PyList_Size(list); i++) {
+ PyObject *item = PyList_GetItem(list, i);
+ if (!PyString_Check(item)) {
+ PyErr_Format(PyExc_TypeError, "%s should be strings", paramname);
+ return NULL;
+ }
+ ret[i] = talloc_strndup(ret, PyString_AsString(item),
+ PyString_Size(item));
+ }
+
+ ret[i] = NULL;
+ return ret;
+}
+
+/*
+ * The sss.local object
+ */
+typedef struct {
+ PyObject_HEAD
+
+ TALLOC_CTX *mem_ctx;
+ struct tevent_context *ev;
+ struct sysdb_ctx *sysdb;
+ struct confdb_ctx *confdb;
+
+ struct sss_domain_info *local;
+
+ int lock;
+ int unlock;
+} PySssLocalObject;
+
+/*
+ * The transaction object
+ */
+struct py_sss_transaction {
+ PySssLocalObject *self;
+ struct ops_ctx *ops;
+
+ struct sysdb_handle *handle;
+ bool transaction_done;
+ int error;
+};
+
+/*
+ * Error reporting
+ */
+static void PyErr_SetSssErrorWithMessage(int ret, const char *message)
+{
+ PyObject *exc = Py_BuildValue(discard_const_p(char, "(is)"),
+ ret, message);
+
+ PyErr_SetObject(PyExc_IOError, exc);
+ Py_XDECREF(exc);
+}
+
+static void PyErr_SetSssError(int ret)
+{
+ PyErr_SetSssErrorWithMessage(ret, strerror(ret));
+}
+
+/*
+ * Common init of all methods
+ */
+struct tools_ctx *init_ctx(TALLOC_CTX *mem_ctx,
+ PySssLocalObject *self)
+{
+ struct ops_ctx *octx = NULL;
+ struct tools_ctx *tctx = NULL;
+
+ tctx = talloc_zero(self->mem_ctx, struct tools_ctx);
+ if (tctx == NULL) {
+ return NULL;
+ }
+
+ tctx->ev = self->ev;
+ tctx->confdb = self->confdb;
+ tctx->sysdb = self->sysdb;
+ tctx->local = self->local;
+ /* tctx->nctx is NULL here, which is OK since we don't parse domains
+ * in the python bindings (yet?) */
+
+ octx = talloc_zero(tctx, struct ops_ctx);
+ if (octx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ octx->domain = self->local;
+
+ tctx->octx = octx;
+ return tctx;
+}
+
+/*
+ * Add a user
+ */
+PyDoc_STRVAR(py_sss_useradd__doc__,
+ "Add a user named ``username``.\n\n"
+ ":param username: name of the user\n\n"
+ ":param kwargs: Keyword arguments that customize the operation\n\n"
+ "* useradd can be customized further with keyword arguments:\n"
+ " * ``uid``: The UID of the user\n"
+ " * ``gid``: The GID of the user\n"
+ " * ``gecos``: The comment string\n"
+ " * ``homedir``: Home directory\n"
+ " * ``shell``: Login shell\n"
+ " * ``skel``: Specify an alternative skeleton directory\n"
+ " * ``create_home``: (bool) Force creation of home directory on or off\n"
+ " * ``groups``: List of groups the user is member of\n");
+
+
+static PyObject *py_sss_useradd(PySssLocalObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ struct tools_ctx *tctx = NULL;
+ unsigned long uid = 0;
+ unsigned long gid = 0;
+ const char *gecos = NULL;
+ const char *home = NULL;
+ const char *shell = NULL;
+ const char *skel = NULL;
+ char *username = NULL;
+ int ret;
+ const char * const kwlist[] = { "username", "uid", "gid", "gecos",
+ "homedir", "shell", "skel",
+ "create_home", "groups", NULL };
+ PyObject *py_groups = Py_None;
+ PyObject *py_create_home = Py_None;
+ int create_home = 0;
+
+ /* parse arguments */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ discard_const_p(char, "s|kkssssO!O!"),
+ discard_const_p(char *, kwlist),
+ &username,
+ &uid,
+ &gid,
+ &gecos,
+ &home,
+ &shell,
+ &skel,
+ &PyBool_Type,
+ &py_create_home,
+ &PyList_Type,
+ &py_groups)) {
+ goto fail;
+ }
+
+ tctx = init_ctx(self->mem_ctx, self);
+ if (!tctx) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (py_groups != Py_None) {
+ tctx->octx->addgroups = PyList_AsStringList(tctx, py_groups, "groups");
+ if (!tctx->octx->addgroups) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ }
+
+ /* user-wise the parameter is only bool - do or don't,
+ * however we must have a third state - undecided, pick default */
+ if (py_create_home == Py_True) {
+ create_home = DO_CREATE_HOME;
+ } else if (py_create_home == Py_False) {
+ create_home = DO_NOT_CREATE_HOME;
+ }
+
+ tctx->octx->name = username;
+ tctx->octx->uid = uid;
+
+ /* fill in defaults */
+ ret = useradd_defaults(tctx,
+ self->confdb,
+ tctx->octx, gecos,
+ home, shell,
+ create_home,
+ skel);
+ if (ret != EOK) {
+ PyErr_SetSssError(ret);
+ goto fail;
+ }
+
+ /* Add the user within a transaction */
+ start_transaction(tctx);
+ if (tctx->error != EOK) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ /* useradd */
+ ret = useradd(tctx, self->ev,
+ self->sysdb, tctx->handle, tctx->octx);
+ if (ret != EOK) {
+ tctx->error = ret;
+
+ /* cancel transaction */
+ talloc_zfree(tctx->handle);
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ end_transaction(tctx);
+ if (tctx->error) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ /* Create user's home directory and/or mail spool */
+ if (tctx->octx->create_homedir) {
+ /* We need to know the UID and GID of the user, if
+ * sysdb did assign it automatically, do a lookup */
+ if (tctx->octx->uid == 0 || tctx->octx->gid == 0) {
+ ret = sysdb_getpwnam_sync(tctx,
+ tctx->ev,
+ tctx->sysdb,
+ tctx->octx->name,
+ tctx->local,
+ &tctx->octx);
+ if (ret != EOK) {
+ PyErr_SetSssError(ret);
+ goto fail;
+ }
+ }
+
+ ret = create_homedir(tctx,
+ tctx->octx->skeldir,
+ tctx->octx->home,
+ tctx->octx->name,
+ tctx->octx->uid,
+ tctx->octx->gid,
+ tctx->octx->umask);
+ if (ret != EOK) {
+ PyErr_SetSssError(ret);
+ goto fail;
+ }
+
+ /* failure here should not be fatal */
+ create_mail_spool(tctx,
+ tctx->octx->name,
+ tctx->octx->maildir,
+ tctx->octx->uid,
+ tctx->octx->gid);
+ }
+
+ talloc_zfree(tctx);
+ Py_RETURN_NONE;
+
+fail:
+ talloc_zfree(tctx);
+ return NULL;
+}
+
+/*
+ * Delete a user
+ */
+PyDoc_STRVAR(py_sss_userdel__doc__,
+ "Remove the user named ``username``.\n\n"
+ ":param username: Name of user being removed\n"
+ ":param kwargs: Keyword arguments that customize the operation\n\n"
+ "* userdel can be customized further with keyword arguments:\n"
+ " * ``force``: (bool) Force removal of files not owned by the user\n"
+ " * ``remove``: (bool) Toggle removing home directory and mail spool\n");
+
+static PyObject *py_sss_userdel(PySssLocalObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ struct tools_ctx *tctx = NULL;
+ char *username = NULL;
+ int ret;
+ PyObject *py_remove = Py_None;
+ int remove_home = 0;
+ PyObject *py_force = Py_None;
+ const char * const kwlist[] = { "username", "remove", "force", NULL };
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds,
+ discard_const_p(char, "s|O!O!"),
+ discard_const_p(char *, kwlist),
+ &username,
+ &PyBool_Type,
+ &py_remove,
+ &PyBool_Type,
+ &py_force)) {
+ goto fail;
+ }
+
+ tctx = init_ctx(self->mem_ctx, self);
+ if (!tctx) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ tctx->octx->name = username;
+
+ if (py_remove == Py_True) {
+ remove_home = DO_REMOVE_HOME;
+ } else if (py_remove == Py_False) {
+ remove_home = DO_NOT_REMOVE_HOME;
+ }
+
+ /*
+ * Fills in defaults for ops_ctx user did not specify.
+ */
+ ret = userdel_defaults(tctx,
+ tctx->confdb,
+ tctx->octx,
+ remove_home);
+ if (ret != EOK) {
+ PyErr_SetSssError(ret);
+ goto fail;
+ }
+
+ if (tctx->octx->remove_homedir) {
+ ret = sysdb_getpwnam_sync(tctx,
+ tctx->ev,
+ tctx->sysdb,
+ tctx->octx->name,
+ tctx->local,
+ &tctx->octx);
+ if (ret != EOK) {
+ PyErr_SetSssError(ret);
+ goto fail;
+ }
+ }
+
+ /* Delete the user within a transaction */
+ start_transaction(tctx);
+ if (tctx->error != EOK) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ ret = userdel(tctx, self->ev,
+ self->sysdb, tctx->handle, tctx->octx);
+ if (ret != EOK) {
+ tctx->error = ret;
+
+ /* cancel transaction */
+ talloc_zfree(tctx->handle);
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ end_transaction(tctx);
+ if (tctx->error) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ if (tctx->octx->remove_homedir) {
+ ret = remove_homedir(tctx,
+ tctx->octx->home,
+ tctx->octx->maildir,
+ tctx->octx->name,
+ tctx->octx->uid,
+ (py_force == Py_True));
+ if (ret != EOK) {
+ PyErr_SetSssError(ret);
+ goto fail;
+ }
+ }
+
+ talloc_zfree(tctx);
+ Py_RETURN_NONE;
+
+fail:
+ talloc_zfree(tctx);
+ return NULL;
+}
+
+/*
+ * Modify a user
+ */
+PyDoc_STRVAR(py_sss_usermod__doc__,
+ "Modify a user.\n\n"
+ ":param username: Name of user being modified\n\n"
+ ":param kwargs: Keyword arguments that customize the operation\n\n"
+ "* usermod can be customized further with keyword arguments:\n"
+ " * ``uid``: The UID of the user\n"
+ " * ``gid``: The GID of the user\n"
+ " * ``gecos``: The comment string\n"
+ " * ``homedir``: Home directory\n"
+ " * ``shell``: Login shell\n"
+ " * ``addgroups``: List of groups to add the user to\n"
+ " * ``rmgroups``: List of groups to remove the user from\n"
+ " * ``lock``: Lock or unlock the account\n");
+
+static PyObject *py_sss_usermod(PySssLocalObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ struct tools_ctx *tctx = NULL;
+ int ret;
+ PyObject *py_addgroups = Py_None;
+ PyObject *py_rmgroups = Py_None;
+ unsigned long uid = 0;
+ unsigned long gid = 0;
+ char *gecos = NULL;
+ char *home = NULL;
+ char *shell = NULL;
+ char *username = NULL;
+ unsigned long lock = 0;
+ const char * const kwlist[] = { "username", "uid", "gid", "lock",
+ "gecos", "homedir", "shell",
+ "addgroups", "rmgroups", NULL };
+
+ /* parse arguments */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ discard_const_p(char, "s|kkksssO!O!"),
+ discard_const_p(char *, kwlist),
+ &username,
+ &uid,
+ &gid,
+ &lock,
+ &gecos,
+ &home,
+ &shell,
+ &PyList_Type,
+ &py_addgroups,
+ &PyList_Type,
+ &py_rmgroups)) {
+ goto fail;
+ }
+
+ tctx = init_ctx(self->mem_ctx, self);
+ if (!tctx) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (lock && lock != DO_LOCK && lock != DO_UNLOCK) {
+ PyErr_SetString(PyExc_ValueError,
+ "Unkown value for lock parameter");
+ goto fail;
+ }
+
+ if (py_addgroups != Py_None) {
+ tctx->octx->addgroups = PyList_AsStringList(tctx,
+ py_addgroups,
+ "addgroups");
+ if (!tctx->octx->addgroups) {
+ return NULL;
+ }
+ }
+
+ if (py_rmgroups != Py_None) {
+ tctx->octx->rmgroups = PyList_AsStringList(tctx,
+ py_rmgroups,
+ "rmgroups");
+ if (!tctx->octx->rmgroups) {
+ return NULL;
+ }
+ }
+
+ tctx->octx->name = username;
+ tctx->octx->uid = uid;
+ tctx->octx->gid = gid;
+ tctx->octx->gecos = gecos;
+ tctx->octx->home = home;
+ tctx->octx->shell = shell;
+ tctx->octx->lock = lock;
+
+ /* Modify the user within a transaction */
+ start_transaction(tctx);
+ if (tctx->error != EOK) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ /* usermod */
+ ret = usermod(tctx, self->ev,
+ self->sysdb, tctx->handle, tctx->octx);
+ if (ret != EOK) {
+ tctx->error = ret;
+
+ /* cancel transaction */
+ talloc_zfree(tctx->handle);
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ end_transaction(tctx);
+ if (tctx->error) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ talloc_zfree(tctx);
+ Py_RETURN_NONE;
+
+fail:
+ talloc_zfree(tctx);
+ return NULL;
+}
+
+/*
+ * Add a group
+ */
+PyDoc_STRVAR(py_sss_groupadd__doc__,
+ "Add a group.\n\n"
+ ":param groupname: Name of group being added\n\n"
+ ":param kwargs: Keyword arguments ro customize the operation\n\n"
+ "* groupmod can be customized further with keyword arguments:\n"
+ " * ``gid``: The GID of the group\n");
+
+static PyObject *py_sss_groupadd(PySssLocalObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ struct tools_ctx *tctx = NULL;
+ char *groupname;
+ unsigned long gid = 0;
+ int ret;
+ const char * const kwlist[] = { "groupname", "gid", NULL };
+
+ /* parse arguments */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ discard_const_p(char, "s|k"),
+ discard_const_p(char *, kwlist),
+ &groupname,
+ &gid)) {
+ goto fail;
+ }
+
+ tctx = init_ctx(self->mem_ctx, self);
+ if (!tctx) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ tctx->octx->name = groupname;
+ tctx->octx->gid = gid;
+
+ /* Add the group within a transaction */
+ start_transaction(tctx);
+ if (tctx->error != EOK) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ /* groupadd */
+ ret = groupadd(tctx, self->ev,
+ self->sysdb, tctx->handle, tctx->octx);
+ if (ret != EOK) {
+ tctx->error = ret;
+
+ /* cancel transaction */
+ talloc_zfree(tctx->handle);
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ end_transaction(tctx);
+ if (tctx->error) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ talloc_zfree(tctx);
+ Py_RETURN_NONE;
+
+fail:
+ talloc_zfree(tctx);
+ return NULL;
+}
+
+/*
+ * Delete a group
+ */
+PyDoc_STRVAR(py_sss_groupdel__doc__,
+ "Remove a group.\n\n"
+ ":param groupname: Name of group being removed\n");
+
+static PyObject *py_sss_groupdel(PySssLocalObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ struct tools_ctx *tctx = NULL;
+ char *groupname = NULL;
+ int ret;
+
+ if(!PyArg_ParseTuple(args, discard_const_p(char, "s"), &groupname)) {
+ goto fail;
+ }
+
+ tctx = init_ctx(self->mem_ctx, self);
+ if (!tctx) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ tctx->octx->name = groupname;
+
+ /* Remove the group within a transaction */
+ start_transaction(tctx);
+ if (tctx->error != EOK) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ /* groupdel */
+ ret = groupdel(tctx, self->ev,
+ self->sysdb, tctx->handle, tctx->octx);
+ if (ret != EOK) {
+ tctx->error = ret;
+
+ /* cancel transaction */
+ talloc_zfree(tctx->handle);
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ end_transaction(tctx);
+ if (tctx->error) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ talloc_zfree(tctx);
+ Py_RETURN_NONE;
+
+fail:
+ talloc_zfree(tctx);
+ return NULL;
+}
+
+/*
+ * Modify a group
+ */
+PyDoc_STRVAR(py_sss_groupmod__doc__,
+"Modify a group.\n\n"
+":param groupname: Name of group being modified\n\n"
+":param kwargs: Keyword arguments ro customize the operation\n\n"
+"* groupmod can be customized further with keyword arguments:\n"
+" * ``gid``: The GID of the group\n\n"
+" * ``addgroups``: Groups to add the group to\n\n"
+" * ``rmgroups``: Groups to remove the group from\n\n");
+
+static PyObject *py_sss_groupmod(PySssLocalObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ struct tools_ctx *tctx = NULL;
+ int ret;
+ PyObject *py_addgroups = Py_None;
+ PyObject *py_rmgroups = Py_None;
+ unsigned long gid = 0;
+ char *groupname = NULL;
+ const char * const kwlist[] = { "groupname", "gid", "addgroups",
+ "rmgroups", NULL };
+
+ /* parse arguments */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ discard_const_p(char, "s|kO!O!"),
+ discard_const_p(char *, kwlist),
+ &groupname,
+ &gid,
+ &PyList_Type,
+ &py_addgroups,
+ &PyList_Type,
+ &py_rmgroups)) {
+ goto fail;
+ }
+
+ tctx = init_ctx(self->mem_ctx, self);
+ if (!tctx) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (py_addgroups != Py_None) {
+ tctx->octx->addgroups = PyList_AsStringList(tctx,
+ py_addgroups,
+ "addgroups");
+ if (!tctx->octx->addgroups) {
+ return NULL;
+ }
+ }
+
+ if (py_rmgroups != Py_None) {
+ tctx->octx->rmgroups = PyList_AsStringList(tctx,
+ py_rmgroups,
+ "rmgroups");
+ if (!tctx->octx->rmgroups) {
+ return NULL;
+ }
+ }
+
+ tctx->octx->name = groupname;
+ tctx->octx->gid = gid;
+
+ /* Modify the group within a transaction */
+ start_transaction(tctx);
+ if (tctx->error != EOK) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ /* groupmod */
+ ret = groupmod(tctx, self->ev,
+ self->sysdb, tctx->handle, tctx->octx);
+ if (ret != EOK) {
+ tctx->error = ret;
+
+ /* cancel transaction */
+ talloc_zfree(tctx->handle);
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ end_transaction(tctx);
+ if (tctx->error) {
+ PyErr_SetSssError(tctx->error);
+ goto fail;
+ }
+
+ talloc_zfree(tctx);
+ Py_RETURN_NONE;
+
+fail:
+ talloc_zfree(tctx);
+ return NULL;
+}
+
+
+/*** python plumbing begins here ***/
+
+/*
+ * The sss.local destructor
+ */
+static void PySssLocalObject_dealloc(PySssLocalObject *self)
+{
+ talloc_free(self->mem_ctx);
+ self->ob_type->tp_free((PyObject*) self);
+}
+
+/*
+ * The sss.local constructor
+ */
+static PyObject *PySssLocalObject_new(PyTypeObject *type,
+ PyObject *args,
+ PyObject *kwds)
+{
+ TALLOC_CTX *mem_ctx;
+ PySssLocalObject *self;
+ char *confdb_path;
+ int ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ self = (PySssLocalObject *) type->tp_alloc(type, 0);
+ if (self == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ self->mem_ctx = mem_ctx;
+
+ self->ev = tevent_context_init(mem_ctx);
+ if (self->ev == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_SetSssErrorWithMessage(EIO, "Cannot create event context");
+ return NULL;
+ }
+
+ confdb_path = talloc_asprintf(self->mem_ctx, "%s/%s", DB_PATH, CONFDB_FILE);
+ if (confdb_path == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ /* Connect to the conf db */
+ ret = confdb_init(self->mem_ctx, &self->confdb, confdb_path);
+ if (ret != EOK) {
+ talloc_free(mem_ctx);
+ PyErr_SetSssErrorWithMessage(ret,
+ "Could not initialize connection to the confdb\n");
+ return NULL;
+ }
+
+ ret = confdb_get_domain(self->confdb, "local", &self->local);
+ if (ret != EOK) {
+ talloc_free(mem_ctx);
+ PyErr_SetSssErrorWithMessage(ret, "Cannot get local domain");
+ return NULL;
+ }
+
+ /* open 'local' sysdb at default path */
+ ret = sysdb_domain_init(self->mem_ctx, self->ev, self->local, DB_PATH, &self->sysdb);
+ if (ret != EOK) {
+ talloc_free(mem_ctx);
+ PyErr_SetSssErrorWithMessage(ret,
+ "Could not initialize connection to the sysdb\n");
+ return NULL;
+ }
+
+ self->lock = DO_LOCK;
+ self->unlock = DO_UNLOCK;
+
+ return (PyObject *) self;
+}
+
+/*
+ * sss.local object methods
+ */
+static PyMethodDef sss_local_methods[] = {
+ { "useradd", (PyCFunction) py_sss_useradd,
+ METH_KEYWORDS, py_sss_useradd__doc__
+ },
+ { "userdel", (PyCFunction) py_sss_userdel,
+ METH_KEYWORDS, py_sss_userdel__doc__
+ },
+ { "usermod", (PyCFunction) py_sss_usermod,
+ METH_KEYWORDS, py_sss_usermod__doc__
+ },
+ { "groupadd", (PyCFunction) py_sss_groupadd,
+ METH_KEYWORDS, py_sss_groupadd__doc__
+ },
+ { "groupdel", (PyCFunction) py_sss_groupdel,
+ METH_KEYWORDS, py_sss_groupdel__doc__
+ },
+ { "groupmod", (PyCFunction) py_sss_groupmod,
+ METH_KEYWORDS, py_sss_groupmod__doc__
+ },
+ {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+static PyMemberDef sss_members[] = {
+ { discard_const_p(char, "lock"), T_INT,
+ offsetof(PySssLocalObject, lock), RO },
+ { discard_const_p(char, "unlock"), T_INT,
+ offsetof(PySssLocalObject, unlock), RO },
+ {NULL} /* Sentinel */
+};
+
+/*
+ * sss.local object properties
+ */
+static PyTypeObject pysss_local_type = {
+ PyObject_HEAD_INIT(NULL)
+ .tp_name = "sss.local",
+ .tp_basicsize = sizeof(PySssLocalObject),
+ .tp_new = PySssLocalObject_new,
+ .tp_dealloc = (destructor) PySssLocalObject_dealloc,
+ .tp_methods = sss_local_methods,
+ .tp_members = sss_members,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_doc = "SSS DB manipulation",
+};
+
+/*
+ * Module methods
+ */
+static PyMethodDef module_methods[] = {
+ {NULL} /* Sentinel */
+};
+
+/*
+ * Module initialization
+ */
+PyMODINIT_FUNC
+initpysss(void)
+{
+ PyObject *m;
+
+ if (PyType_Ready(&pysss_local_type) < 0)
+ return;
+
+ m = Py_InitModule(discard_const_p(char, "pysss"), module_methods);
+ if (m == NULL)
+ return;
+
+ Py_INCREF(&pysss_local_type);
+ PyModule_AddObject(m, discard_const_p(char, "local"), (PyObject *)&pysss_local_type);
+}
+