>From 577a54c97986e2062c4f4da493b23a9aa8292ac1 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 30 Sep 2009 15:17:56 +0200
Subject: [PATCH] Fix python sync operations and mem hierarchy

Similar to Simo's patch that fixed the tools, this one converts the
python bindings to the start_transaction/end_transaction functions.

Also fixes memory hierarchy so that tools_ctx is allocated in every
operation and used as memory context for the operation instead of
self->mem_ctx which simplifies cleanup.
---
 server/python/pysss.c |  588 ++++++++++++++++---------------------------------
 1 files changed, 191 insertions(+), 397 deletions(-)

diff --git a/server/python/pysss.c b/server/python/pysss.c
index aab1718..9ce082b 100644
--- a/server/python/pysss.c
+++ b/server/python/pysss.c
@@ -114,37 +114,38 @@ static void PyErr_SetSssError(int ret)
 /*
  * Common init of all methods
  */
-struct ops_ctx *init_ctx(PySssLocalObject *self)
+struct tools_ctx *init_ctx(TALLOC_CTX *mem_ctx,
+                           PySssLocalObject *self)
 {
-    struct ops_ctx *ops = NULL;
+    struct ops_ctx *octx = NULL;
+    struct tools_ctx *tctx = NULL;
 
-    ops = talloc_zero(self->mem_ctx, struct ops_ctx);
-    if (ops == NULL) {
-        PyErr_NoMemory();
+    tctx = talloc_zero(self->mem_ctx, struct tools_ctx);
+    if (tctx == NULL) {
         return NULL;
     }
 
-    ops->domain = self->local;
-    return ops;
-}
+    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?) */
 
-/*
- * Common transaction finish
- */
-static void req_done(struct tevent_req *req)
-{
-    struct py_sss_transaction *trs = tevent_req_callback_data(req,
-                                                   struct py_sss_transaction);
+    octx = talloc_zero(tctx, struct ops_ctx);
+    if (octx == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    octx->domain = self->local;
 
-    trs->error = sysdb_transaction_commit_recv(req);
-    trs->transaction_done = true;
+    tctx->octx = octx;
+    return tctx;
 }
 
 /*
  * Add a user
  */
-static void py_sss_useradd_transaction(struct tevent_req *req);
-
 PyDoc_STRVAR(py_sss_useradd__doc__,
     "Add a user named ``username``.\n\n"
     ":param username: name of the user\n\n"
@@ -162,9 +163,7 @@ static PyObject *py_sss_useradd(PySssLocalObject *self,
                                 PyObject *args,
                                 PyObject *kwds)
 {
-    struct ops_ctx *ops = NULL;
-    struct py_sss_transaction *trs = NULL;
-    struct tevent_req *req;
+    struct tools_ctx *tctx = NULL;
     unsigned long uid = 0;
     unsigned long gid = 0;
     const char *gecos = NULL;
@@ -190,101 +189,69 @@ static PyObject *py_sss_useradd(PySssLocalObject *self,
         goto fail;
     }
 
-    ops = init_ctx(self);
-    if (!ops) {
+    tctx = init_ctx(self->mem_ctx, self);
+    if (!tctx) {
+        PyErr_NoMemory();
         return NULL;
     }
 
     if (py_groups != Py_None) {
-        ops->addgroups = PyList_AsStringList(self->mem_ctx, py_groups, "groups");
-        if (!ops->addgroups) {
+        tctx->octx->addgroups = PyList_AsStringList(tctx, py_groups, "groups");
+        if (!tctx->octx->addgroups) {
+            PyErr_NoMemory();
             return NULL;
         }
     }
 
-    ops->name = username;
-    ops->uid = uid;
+    tctx->octx->name = username;
+    tctx->octx->uid = uid;
 
     /* fill in defaults */
-    ret = useradd_defaults(self->mem_ctx,
+    ret = useradd_defaults(tctx,
                            self->confdb,
-                           ops, gecos,
+                           tctx->octx, gecos,
                            home, shell);
     if (ret != EOK) {
         PyErr_SetSssError(ret);
         goto fail;
     }
 
-    /* add the user within a sysdb transaction */
-    trs = talloc_zero(self->mem_ctx, struct py_sss_transaction);
-    if (!trs) {
-        PyErr_NoMemory();
-        return NULL;
-    }
-    trs->self = self;
-    trs->ops = ops;
-
-    req = sysdb_transaction_send(self->mem_ctx, self->ev, self->sysdb);
-    if (!req) {
-        DEBUG(1, ("Could not start transaction"));
-        PyErr_NoMemory();
+    /* Add the user within a transaction */
+    start_transaction(tctx);
+    if (tctx->error != EOK) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(req, py_sss_useradd_transaction, trs);
-
-    TRANSACTION_WAIT(trs, ret);
-
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    Py_RETURN_NONE;
-
-fail:
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    return NULL;
-}
-
-static void py_sss_useradd_transaction(struct tevent_req *req)
-{
-    int ret;
-    struct py_sss_transaction *trs = tevent_req_callback_data(req,
-                                                    struct py_sss_transaction);
-    struct tevent_req *subreq;
-
-    ret = sysdb_transaction_recv(req, trs, &trs->handle);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
-    }
-    talloc_zfree(req);
 
     /* useradd */
-    ret = useradd(trs->self->mem_ctx, trs->self->ev,
-                  trs->self->sysdb, trs->handle, trs->ops);
+    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;
     }
 
-    subreq = sysdb_transaction_commit_send(trs->self->mem_ctx, trs->self->ev, trs->handle);
-    if (!subreq) {
-        ret = ENOMEM;
+    end_transaction(tctx);
+    if (tctx->error) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(subreq, req_done, trs);
-    return;
+
+    talloc_zfree(tctx);
+    Py_RETURN_NONE;
 
 fail:
-    /* free transaction and signal error */
-    talloc_zfree(trs->handle);
-    trs->transaction_done = true;
-    trs->error = ret;
+    talloc_zfree(tctx);
+    return NULL;
 }
 
 /*
  * Delete a user
  */
-static void py_sss_userdel_transaction(struct tevent_req *);
-
 PyDoc_STRVAR(py_sss_userdel__doc__,
     "Remove the user named ``username``.\n\n"
     ":param username: Name of user being removed\n");
@@ -293,9 +260,7 @@ static PyObject *py_sss_userdel(PySssLocalObject *self,
                                 PyObject *args,
                                 PyObject *kwds)
 {
-    struct ops_ctx *ops = NULL;
-    struct tevent_req *req;
-    struct py_sss_transaction *trs = NULL;
+    struct tools_ctx *tctx = NULL;
     char *username = NULL;
     int ret;
 
@@ -303,83 +268,49 @@ static PyObject *py_sss_userdel(PySssLocalObject *self,
         goto fail;
     }
 
-    ops = init_ctx(self);
-    if (!ops) {
-        return NULL;
-    }
-
-    ops->name = username;
-
-    /* delete the user within a sysdb transaction */
-    trs = talloc_zero(self->mem_ctx, struct py_sss_transaction);
-    if (!trs) {
+    tctx = init_ctx(self->mem_ctx, self);
+    if (!tctx) {
         PyErr_NoMemory();
         return NULL;
     }
-    trs->self = self;
-    trs->ops = ops;
-
-    req = sysdb_transaction_send(self->mem_ctx, self->ev, self->sysdb);
-    if (!req) {
-        DEBUG(1, ("Could not start transaction"));
-        PyErr_NoMemory();
-        goto fail;
-    }
-    tevent_req_set_callback(req, py_sss_userdel_transaction, trs);
-
-    TRANSACTION_WAIT(trs, ret);
-
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    Py_RETURN_NONE;
 
-fail:
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    return NULL;
-}
-
-static void py_sss_userdel_transaction(struct tevent_req *req)
-{
-    int ret;
-    struct py_sss_transaction *trs = tevent_req_callback_data(req,
-                                                    struct py_sss_transaction);
-    struct tevent_req *subreq;
+    tctx->octx->name = username;
 
-    ret = sysdb_transaction_recv(req, trs, &trs->handle);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
+    /* Delete the user within a transaction */
+    start_transaction(tctx);
+    if (tctx->error != EOK) {
+        PyErr_SetSssError(tctx->error);
+        goto fail;
     }
-    talloc_zfree(req);
 
-    /* userdel */
-    ret = userdel(trs->self->mem_ctx, trs->self->ev,
-                  trs->self->sysdb, trs->handle, trs->ops);
+    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;
     }
 
-    subreq = sysdb_transaction_commit_send(trs->self->mem_ctx, trs->self->ev, trs->handle);
-    if (!subreq) {
-        ret = ENOMEM;
+    end_transaction(tctx);
+    if (tctx->error) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(subreq, req_done, trs);
-    return;
+
+    talloc_zfree(tctx);
+    Py_RETURN_NONE;
 
 fail:
-    /* free transaction and signal error */
-    talloc_zfree(trs->handle);
-    trs->transaction_done = true;
-    trs->error = ret;
+    talloc_zfree(tctx);
+    return NULL;
 }
 
 /*
  * Modify a user
  */
-static void py_sss_usermod_transaction(struct tevent_req *);
-
 PyDoc_STRVAR(py_sss_usermod__doc__,
     "Modify a user.\n\n"
     ":param username: Name of user being modified\n\n"
@@ -398,9 +329,7 @@ static PyObject *py_sss_usermod(PySssLocalObject *self,
                                 PyObject *args,
                                 PyObject *kwds)
 {
-    struct ops_ctx *ops = NULL;
-    struct tevent_req *req;
-    struct py_sss_transaction *trs = NULL;
+    struct tools_ctx *tctx = NULL;
     int ret;
     PyObject *py_addgroups = Py_None;
     PyObject *py_rmgroups = Py_None;
@@ -432,8 +361,9 @@ static PyObject *py_sss_usermod(PySssLocalObject *self,
         goto fail;
     }
 
-    ops = init_ctx(self);
-    if (!ops) {
+    tctx = init_ctx(self->mem_ctx, self);
+    if (!tctx) {
+        PyErr_NoMemory();
         return NULL;
     }
 
@@ -444,100 +374,67 @@ static PyObject *py_sss_usermod(PySssLocalObject *self,
     }
 
     if (py_addgroups != Py_None) {
-        ops->addgroups = PyList_AsStringList(self->mem_ctx,
-                                             py_addgroups,
-                                             "addgroups");
-        if (!ops->addgroups) {
+        tctx->octx->addgroups = PyList_AsStringList(tctx,
+                                                    py_addgroups,
+                                                    "addgroups");
+        if (!tctx->octx->addgroups) {
             return NULL;
         }
     }
 
     if (py_rmgroups != Py_None) {
-        ops->rmgroups = PyList_AsStringList(self->mem_ctx,
-                                            py_rmgroups,
-                                            "rmgroups");
-        if (!ops->rmgroups) {
+        tctx->octx->rmgroups = PyList_AsStringList(tctx,
+                                                   py_rmgroups,
+                                                   "rmgroups");
+        if (!tctx->octx->rmgroups) {
             return NULL;
         }
     }
 
-    ops->name  = username;
-    ops->uid   = uid;
-    ops->gid   = gid;
-    ops->gecos = gecos;
-    ops->home  = home;
-    ops->shell = shell;
-    ops->lock  = lock;
-
-    /* modify the user within a sysdb transaction */
-    trs = talloc_zero(self->mem_ctx, struct py_sss_transaction);
-    if (!trs) {
-        PyErr_NoMemory();
-        return NULL;
-    }
-    trs->self = self;
-    trs->ops = ops;
+    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;
 
-    req = sysdb_transaction_send(self->mem_ctx, self->ev, self->sysdb);
-    if (!req) {
-        DEBUG(1, ("Could not start transaction"));
-        PyErr_NoMemory();
+    /* Modify the user within a transaction */
+    start_transaction(tctx);
+    if (tctx->error != EOK) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(req, py_sss_usermod_transaction, trs);
-
-    TRANSACTION_WAIT(trs, ret);
-
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    Py_RETURN_NONE;
 
-fail:
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    return NULL;
-}
-
-static void py_sss_usermod_transaction(struct tevent_req *req)
-{
-    int ret;
-    struct py_sss_transaction *trs = tevent_req_callback_data(req,
-                                                    struct py_sss_transaction);
-    struct tevent_req *subreq;
-
-    ret = sysdb_transaction_recv(req, trs, &trs->handle);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
-    }
-    talloc_zfree(req);
     /* usermod */
-    ret = usermod(trs->self->mem_ctx, trs->self->ev,
-                  trs->self->sysdb, trs->handle, trs->ops);
+    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;
     }
 
-    subreq = sysdb_transaction_commit_send(trs->self->mem_ctx, trs->self->ev, trs->handle);
-    if (!subreq) {
-        ret = ENOMEM;
+    end_transaction(tctx);
+    if (tctx->error) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(subreq, req_done, trs);
-    return;
+
+    talloc_zfree(tctx);
+    Py_RETURN_NONE;
 
 fail:
-    /* free transaction and signal error */
-    talloc_zfree(trs->handle);
-    trs->transaction_done = true;
-    trs->error = ret;
+    talloc_zfree(tctx);
+    return NULL;
 }
 
 /*
  * Add a group
  */
-static void py_sss_groupadd_transaction(struct tevent_req *);
-
 PyDoc_STRVAR(py_sss_groupadd__doc__,
     "Add a group.\n\n"
     ":param groupname: Name of group being added\n\n"
@@ -549,9 +446,7 @@ static PyObject *py_sss_groupadd(PySssLocalObject *self,
                                  PyObject *args,
                                  PyObject *kwds)
 {
-    struct ops_ctx *ops = NULL;
-    struct tevent_req *req;
-    struct py_sss_transaction *trs = NULL;
+    struct tools_ctx *tctx = NULL;
     char *groupname;
     unsigned long gid = 0;
     int ret;
@@ -565,84 +460,51 @@ static PyObject *py_sss_groupadd(PySssLocalObject *self,
         goto fail;
     }
 
-    ops = init_ctx(self);
-    if (!ops) {
-        return NULL;
-    }
-
-    ops->name  = groupname;
-    ops->gid = gid;
-
-    /* add the group within a sysdb transaction */
-    trs = talloc_zero(self->mem_ctx, struct py_sss_transaction);
-    if (!trs) {
+    tctx = init_ctx(self->mem_ctx, self);
+    if (!tctx) {
         PyErr_NoMemory();
         return NULL;
     }
-    trs->self = self;
-    trs->ops = ops;
-
-    req = sysdb_transaction_send(self->mem_ctx, self->ev, self->sysdb);
-    if (!req) {
-        DEBUG(1, ("Could not start transaction"));
-        PyErr_NoMemory();
-        goto fail;
-    }
-    tevent_req_set_callback(req, py_sss_groupadd_transaction, trs);
-
-    TRANSACTION_WAIT(trs, ret);
-
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    Py_RETURN_NONE;
 
-fail:
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    return NULL;
-}
+    tctx->octx->name = groupname;
+    tctx->octx->gid = gid;
 
-static void py_sss_groupadd_transaction(struct tevent_req *req)
-{
-    int ret;
-    struct py_sss_transaction *trs = tevent_req_callback_data(req,
-                                                    struct py_sss_transaction);
-    struct tevent_req *subreq;
-
-    ret = sysdb_transaction_recv(req, trs, &trs->handle);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
+    /* Add the group within a transaction */
+    start_transaction(tctx);
+    if (tctx->error != EOK) {
+        PyErr_SetSssError(tctx->error);
+        goto fail;
     }
-    talloc_zfree(req);
 
     /* groupadd */
-    ret = groupadd(trs->self->mem_ctx, trs->self->ev,
-                          trs->self->sysdb, trs->handle, trs->ops);
+    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;
     }
 
-    subreq = sysdb_transaction_commit_send(trs->self->mem_ctx, trs->self->ev, trs->handle);
-    if (!subreq) {
-        ret = ENOMEM;
+    end_transaction(tctx);
+    if (tctx->error) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(subreq, req_done, trs);
-    return;
+
+    talloc_zfree(tctx);
+    Py_RETURN_NONE;
 
 fail:
-    /* free transaction and signal error */
-    talloc_zfree(trs->handle);
-    trs->transaction_done = true;
-    trs->error = ret;
+    talloc_zfree(tctx);
+    return NULL;
 }
 
 /*
  * Delete a group
  */
-static void py_sss_groupdel_transaction(struct tevent_req *req);
-
 PyDoc_STRVAR(py_sss_groupdel__doc__,
     "Remove a group.\n\n"
     ":param groupname: Name of group being removed\n");
@@ -651,9 +513,7 @@ static PyObject *py_sss_groupdel(PySssLocalObject *self,
                                 PyObject *args,
                                 PyObject *kwds)
 {
-    struct ops_ctx *ops = NULL;
-    struct tevent_req *req;
-    struct py_sss_transaction *trs = NULL;
+    struct tools_ctx *tctx = NULL;
     char *groupname = NULL;
     int ret;
 
@@ -661,83 +521,50 @@ static PyObject *py_sss_groupdel(PySssLocalObject *self,
         goto fail;
     }
 
-    ops = init_ctx(self);
-    if (!ops) {
-        return NULL;
-    }
-
-    ops->name  = groupname;
-
-    /* delete the group within a sysdb transaction */
-    trs = talloc_zero(self->mem_ctx, struct py_sss_transaction);
-    if (!trs) {
+    tctx = init_ctx(self->mem_ctx, self);
+    if (!tctx) {
         PyErr_NoMemory();
         return NULL;
     }
-    trs->self = self;
-    trs->ops = ops;
-
-    req = sysdb_transaction_send(self->mem_ctx, self->ev, self->sysdb);
-    if (!req) {
-        DEBUG(1, ("Could not start transaction"));
-        PyErr_NoMemory();
-        goto fail;
-    }
-    tevent_req_set_callback(req, py_sss_groupdel_transaction, trs);
-
-    TRANSACTION_WAIT(trs, ret);
-
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    Py_RETURN_NONE;
-
-fail:
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    return NULL;
-}
 
-static void py_sss_groupdel_transaction(struct tevent_req *req)
-{
-    int ret;
-    struct py_sss_transaction *trs = tevent_req_callback_data(req,
-                                                    struct py_sss_transaction);
-    struct tevent_req *subreq;
+    tctx->octx->name = groupname;
 
-    ret = sysdb_transaction_recv(req, trs, &trs->handle);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
+    /* Remove the group within a transaction */
+    start_transaction(tctx);
+    if (tctx->error != EOK) {
+        PyErr_SetSssError(tctx->error);
+        goto fail;
     }
-    talloc_zfree(req);
 
     /* groupdel */
-    ret = groupdel(trs->self->mem_ctx, trs->self->ev,
-                          trs->self->sysdb, trs->handle, trs->ops);
+    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;
     }
 
-    subreq = sysdb_transaction_commit_send(trs->self->mem_ctx, trs->self->ev, trs->handle);
-    if (!subreq) {
-        ret = ENOMEM;
+    end_transaction(tctx);
+    if (tctx->error) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(subreq, req_done, trs);
-    return;
+
+    talloc_zfree(tctx);
+    Py_RETURN_NONE;
 
 fail:
-    /* free transaction and signal error */
-    talloc_zfree(trs->handle);
-    trs->transaction_done = true;
-    trs->error = ret;
+    talloc_zfree(tctx);
+    return NULL;
 }
 
 /*
  * Modify a group
  */
-static void py_sss_groupmod_transaction(struct tevent_req *);
-
 PyDoc_STRVAR(py_sss_groupmod__doc__,
 "Modify a group.\n\n"
 ":param groupname: Name of group being modified\n\n"
@@ -751,9 +578,7 @@ static PyObject *py_sss_groupmod(PySssLocalObject *self,
                                 PyObject *args,
                                 PyObject *kwds)
 {
-    struct ops_ctx *ops = NULL;
-    struct tevent_req *req;
-    struct py_sss_transaction *trs = NULL;
+    struct tools_ctx *tctx = NULL;
     int ret;
     PyObject *py_addgroups = Py_None;
     PyObject *py_rmgroups = Py_None;
@@ -774,98 +599,67 @@ static PyObject *py_sss_groupmod(PySssLocalObject *self,
         goto fail;
     }
 
-    ops = init_ctx(self);
-    if (!ops) {
+    tctx = init_ctx(self->mem_ctx, self);
+    if (!tctx) {
+        PyErr_NoMemory();
         return NULL;
     }
 
     if (py_addgroups != Py_None) {
-        ops->addgroups = PyList_AsStringList(self->mem_ctx,
+        tctx->octx->addgroups = PyList_AsStringList(tctx,
                                              py_addgroups,
                                              "addgroups");
-        if (!ops->addgroups) {
+        if (!tctx->octx->addgroups) {
             return NULL;
         }
     }
 
     if (py_rmgroups != Py_None) {
-        ops->rmgroups = PyList_AsStringList(self->mem_ctx,
+        tctx->octx->rmgroups = PyList_AsStringList(tctx,
                                             py_rmgroups,
                                             "rmgroups");
-        if (!ops->rmgroups) {
+        if (!tctx->octx->rmgroups) {
             return NULL;
         }
     }
 
-    ops->name  = groupname;
-    ops->gid = gid;
+    tctx->octx->name = groupname;
+    tctx->octx->gid = gid;
 
-    /* modify the group within a sysdb transaction */
-    trs = talloc_zero(self->mem_ctx, struct py_sss_transaction);
-    if (!trs) {
-        PyErr_NoMemory();
-        return NULL;
-    }
-    trs->self = self;
-    trs->ops = ops;
-
-    req = sysdb_transaction_send(self->mem_ctx, self->ev, self->sysdb);
-    if (!req) {
-        DEBUG(1, ("Could not start transaction"));
-        PyErr_NoMemory();
+    /* Modify the group within a transaction */
+    start_transaction(tctx);
+    if (tctx->error != EOK) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(req, py_sss_groupmod_transaction, trs);
-
-    TRANSACTION_WAIT(trs, ret);
-
-
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    Py_RETURN_NONE;
-
-fail:
-    talloc_zfree(ops);
-    talloc_zfree(trs);
-    return NULL;
-}
-
-static void py_sss_groupmod_transaction(struct tevent_req *req)
-{
-    int ret;
-    struct py_sss_transaction *trs = tevent_req_callback_data(req,
-                                                    struct py_sss_transaction);
-    struct tevent_req *subreq;
-
-    ret = sysdb_transaction_recv(req, trs, &trs->handle);
-    if (ret) {
-        tevent_req_error(req, ret);
-        return;
-    }
-    talloc_zfree(req);
 
     /* groupmod */
-    ret = groupmod(trs->self->mem_ctx, trs->self->ev,
-                          trs->self->sysdb, trs->handle, trs->ops);
+    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;
     }
 
-    subreq = sysdb_transaction_commit_send(trs->self->mem_ctx, trs->self->ev, trs->handle);
-    if (!subreq) {
-        ret = ENOMEM;
+    end_transaction(tctx);
+    if (tctx->error) {
+        PyErr_SetSssError(tctx->error);
         goto fail;
     }
-    tevent_req_set_callback(subreq, req_done, trs);
-    return;
+
+    talloc_zfree(tctx);
+    Py_RETURN_NONE;
 
 fail:
-    /* free transaction and signal error */
-    talloc_zfree(trs->handle);
-    trs->transaction_done = true;
-    trs->error = ret;
+    talloc_zfree(tctx);
+    return NULL;
 }
 
+
 /*** python plumbing begins here ***/
 
 /*
-- 
1.6.2.5

