[SSSD] [PATCH] Cherry-pick Stef's sbus_request patches to sssd-1-11

Jakub Hrozek jhrozek at redhat.com
Mon Jun 2 15:39:29 UTC 2014


Hi,

the attached patchset cherry-picks the sbus_request patches to
sssd-1-11. As with the previous set I sent, I left the conflict messages
in the commit headers. There were only two conflicts, one in the
Makefile (tests again) and one trivial in #include section of one of the
sbus source files.
-------------- next part --------------
>From 0e5514bc5267e56def5dd2e08a3130640947c0fb Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at gnome.org>
Date: Fri, 17 Jan 2014 12:54:42 +0100
Subject: [PATCH 1/5] sbus: Add struct sbus_request to represent a DBus
 invocation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

struct sbus_request represents a request from a dbus client
being handled by a dbus server implementation. The struct
contains the message, connection and method (and in the
future teh property) which is being requested.

In the future it will contain caller information as well.

sbus_request is a talloc memory context, and is a good place to
attach any allocations and memory specific to the request.

Each handler accepts an sbus_request. If a handler returns
EOK, it is assumed that the handler will finish the request.
Any of the sbus_request_*finish() methods can be used to
complete the request and send back a reply.

sbus_request_return_and_finish() uses the same argument
varargs syntax as dbus_message_append_args(), which isn't
a great syntax. Document it a bit, but don't try to redesign:
The marshalling work (will follow this patch set) will remove
the need to use varargs for most DBus implementation code.

This patch migrates the monitor and data provider dbus code
to use sbus_request, but does not try to rework the talloc
context's to use it.

Reviewed-by: Jakub Hrozek <jhrozek at redhat.com>
Reviewed-by: Pavel Březina <pbrezina at redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn at redhat.com>

(cherry picked from commit d9577dbd92555b0755881e37724019ef9c578404)

Conflicts:
	src/sbus/sssd_dbus.h
---
 Makefile.am                             |   1 +
 src/monitor/monitor.c                   |  54 +---
 src/monitor/monitor_interfaces.h        |   6 +-
 src/monitor/monitor_sbus.c              |  26 +-
 src/providers/data_provider_be.c        | 512 ++++++++++++--------------------
 src/providers/proxy/proxy_child.c       |  14 +-
 src/providers/proxy/proxy_init.c        |  38 +--
 src/responder/autofs/autofssrv.c        |  10 +-
 src/responder/common/responder.h        |   3 +-
 src/responder/common/responder_common.c |   7 +-
 src/responder/nss/nsssrv.c              |  50 +---
 src/sbus/sssd_dbus.h                    |  80 ++++-
 src/sbus/sssd_dbus_connection.c         |  46 +--
 src/sbus/sssd_dbus_private.h            |   6 +
 src/sbus/sssd_dbus_request.c            | 112 +++++++
 src/tests/sbus_codegen_tests.c          |   4 +-
 16 files changed, 470 insertions(+), 499 deletions(-)
 create mode 100644 src/sbus/sssd_dbus_request.c

diff --git a/Makefile.am b/Makefile.am
index 0289645c9d52616938f6d693a7857f06837f0f08..01d199ace430ea42e7af1003eb0eb8498243b30d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -568,6 +568,7 @@ libsss_util_la_SOURCES = \
     src/sbus/sssd_dbus_common.c \
     src/sbus/sssd_dbus_connection.c \
     src/sbus/sssd_dbus_meta.c \
+    src/sbus/sssd_dbus_request.c \
     src/sbus/sssd_dbus_server.c \
     src/util/util.c \
     src/util/memory.c \
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 12c3a7702787fafcc1ea2244935f2213b46f6953..956e754254af37cb9ccb0df58ddd3d4269daab1d 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -219,28 +219,13 @@ static void network_status_change_cb(void *cb_data)
 
 /* dbus_get_monitor_version
  * Return the monitor version over D-BUS */
-static int get_monitor_version(DBusMessage *message,
-                               struct sbus_connection *conn)
+static int get_monitor_version(struct sbus_request *dbus_req)
 {
     dbus_uint16_t version = MONITOR_VERSION;
-    DBusMessage *reply;
-    dbus_bool_t ret;
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) return ENOMEM;
-    ret = dbus_message_append_args(reply,
-                                   DBUS_TYPE_UINT16, &version,
-                                   DBUS_TYPE_INVALID);
-    if (!ret) {
-        dbus_message_unref(reply);
-        return EIO;
-    }
-
-    /* send reply back */
-    sbus_conn_send_reply(conn, reply);
-    dbus_message_unref(reply);
-
-    return EOK;
+    return sbus_request_return_and_finish(dbus_req,
+                                          DBUS_TYPE_UINT16, &version,
+                                          DBUS_TYPE_INVALID);
 }
 
 struct mon_init_conn {
@@ -253,21 +238,19 @@ static int add_svc_conn_spy(struct mt_svc *svc);
 
 /* registers a new client.
  * if operation is successful also sends back the Monitor version */
-static int client_registration(DBusMessage *message,
-                               struct sbus_connection *conn)
+static int client_registration(struct sbus_request *dbus_req)
 {
     dbus_uint16_t version = MONITOR_VERSION;
     struct mon_init_conn *mini;
     struct mt_svc *svc;
     void *data;
-    DBusMessage *reply;
     DBusError dbus_error;
     dbus_uint16_t svc_ver;
     char *svc_name;
     dbus_bool_t dbret;
     int ret;
 
-    data = sbus_conn_get_private_data(conn);
+    data = sbus_conn_get_private_data(dbus_req->conn);
     mini = talloc_get_type(data, struct mon_init_conn);
     if (!mini) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
@@ -279,7 +262,7 @@ static int client_registration(DBusMessage *message,
 
     dbus_error_init(&dbus_error);
 
-    dbret = dbus_message_get_args(message, &dbus_error,
+    dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                   DBUS_TYPE_STRING, &svc_name,
                                   DBUS_TYPE_UINT16, &svc_ver,
                                   DBUS_TYPE_INVALID);
@@ -287,7 +270,8 @@ static int client_registration(DBusMessage *message,
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Failed to parse message, killing connection\n");
         if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
-        sbus_disconnect(conn);
+        sbus_disconnect(dbus_req->conn);
+        sbus_request_finish(dbus_req, NULL);
         /* FIXME: should we just talloc_zfree(conn) ? */
         goto done;
     }
@@ -308,7 +292,8 @@ static int client_registration(DBusMessage *message,
         DEBUG(SSSDBG_FATAL_FAILURE,
               "Unable to find peer [%s] in list of services,"
                   " killing connection!\n", svc_name);
-        sbus_disconnect(conn);
+        sbus_disconnect(dbus_req->conn);
+        sbus_request_finish(dbus_req, NULL);
         /* FIXME: should we just talloc_zfree(conn) ? */
         goto done;
     }
@@ -323,20 +308,9 @@ static int client_registration(DBusMessage *message,
     }
 
     /* reply that all is ok */
-    reply = dbus_message_new_method_return(message);
-    if (!reply) return ENOMEM;
-
-    dbret = dbus_message_append_args(reply,
-                                     DBUS_TYPE_UINT16, &version,
-                                     DBUS_TYPE_INVALID);
-    if (!dbret) {
-        dbus_message_unref(reply);
-        return EIO;
-    }
-
-    /* send reply back */
-    sbus_conn_send_reply(conn, reply);
-    dbus_message_unref(reply);
+    sbus_request_return_and_finish(dbus_req,
+                                   DBUS_TYPE_UINT16, &version,
+                                   DBUS_TYPE_INVALID);
 
 done:
     /* init complete, get rid of temp init context */
diff --git a/src/monitor/monitor_interfaces.h b/src/monitor/monitor_interfaces.h
index ef4254a5f59620fe1789135248358bfa6ffe7530..2970251df94e75e5b1f5f746792a6eaf11f9577d 100644
--- a/src/monitor/monitor_interfaces.h
+++ b/src/monitor/monitor_interfaces.h
@@ -38,10 +38,8 @@
 int monitor_get_sbus_address(TALLOC_CTX *mem_ctx, char **address);
 int monitor_common_send_id(struct sbus_connection *conn,
                            const char *name, uint16_t version);
-int monitor_common_pong(DBusMessage *message,
-                        struct sbus_connection *conn);
-int monitor_common_res_init(DBusMessage *message,
-                            struct sbus_connection *conn);
+int monitor_common_pong(struct sbus_request *dbus_req);
+int monitor_common_res_init(struct sbus_request *dbus_req);
 int monitor_common_rotate_logs(struct confdb_ctx *confdb,
                                const char *conf_entry);
 
diff --git a/src/monitor/monitor_sbus.c b/src/monitor/monitor_sbus.c
index b1550bcdd1927d62c55e85d0cca66aad0523c3ab..92d483233bd1cae45949dad1cd84b596cb099cec 100644
--- a/src/monitor/monitor_sbus.c
+++ b/src/monitor/monitor_sbus.c
@@ -144,30 +144,12 @@ int monitor_common_send_id(struct sbus_connection *conn,
     return retval;
 }
 
-int monitor_common_pong(DBusMessage *message,
-                        struct sbus_connection *conn)
+int monitor_common_pong(struct sbus_request *dbus_req)
 {
-    DBusMessage *reply;
-    dbus_bool_t ret;
-
-    reply = dbus_message_new_method_return(message);
-    if (!reply) return ENOMEM;
-
-    ret = dbus_message_append_args(reply, DBUS_TYPE_INVALID);
-    if (!ret) {
-        dbus_message_unref(reply);
-        return EIO;
-    }
-
-    /* send reply back */
-    sbus_conn_send_reply(conn, reply);
-    dbus_message_unref(reply);
-
-    return EOK;
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-int monitor_common_res_init(DBusMessage *message,
-                            struct sbus_connection *conn)
+int monitor_common_res_init(struct sbus_request *dbus_req)
 {
     int ret;
 
@@ -177,7 +159,7 @@ int monitor_common_res_init(DBusMessage *message,
     }
 
     /* Send an empty reply to acknowledge receipt */
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
 errno_t monitor_common_rotate_logs(struct confdb_ctx *confdb,
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index 15b0d1d966cd01f114bfc4e56920f23e4a7866d1..ea3939f7e99d15da50ddc697b58217980dd7712b 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -54,14 +54,10 @@
 #define ACCESS_DENY "deny"
 #define NO_PROVIDER "none"
 
-static int data_provider_res_init(DBusMessage *message,
-                                  struct sbus_connection *conn);
-static int data_provider_go_offline(DBusMessage *message,
-                                    struct sbus_connection *conn);
-static int data_provider_reset_offline(DBusMessage *message,
-                                       struct sbus_connection *conn);
-static int data_provider_logrotate(DBusMessage *message,
-                                struct sbus_connection *conn);
+static int data_provider_res_init(struct sbus_request *dbus_req);
+static int data_provider_go_offline(struct sbus_request *dbus_req);
+static int data_provider_reset_offline(struct sbus_request *dbus_req);
+static int data_provider_logrotate(struct sbus_request *dbus_req);
 
 struct mon_cli_iface monitor_be_methods = {
     { &mon_cli_iface_meta, 0 },
@@ -81,13 +77,13 @@ struct sbus_interface monitor_be_interface = {
     NULL
 };
 
-static int client_registration(DBusMessage *message, struct sbus_connection *conn);
-static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn);
-static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn);
-static int be_sudo_handler(DBusMessage *message, struct sbus_connection *conn);
-static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn);
-static int be_host_handler(DBusMessage *message, struct sbus_connection *conn);
-static int be_get_subdomains(DBusMessage *message, struct sbus_connection *conn);
+static int client_registration(struct sbus_request *dbus_req);
+static int be_get_account_info(struct sbus_request *dbus_req);
+static int be_pam_handler(struct sbus_request *dbus_req);
+static int be_sudo_handler(struct sbus_request *dbus_req);
+static int be_autofs_handler(struct sbus_request *dbus_req);
+static int be_host_handler(struct sbus_request *dbus_req);
+static int be_get_subdomains(struct sbus_request *dbus_req);
 
 struct data_provider_iface be_methods = {
     { &data_provider_iface_meta, 0 },
@@ -401,14 +397,12 @@ static void be_queue_next_request(struct be_req *be_req, enum bet_type type)
     struct bet_queue_item *item;
     struct bet_queue_item *current = NULL;
     struct bet_queue_item **req_queue;
+    struct sbus_request *dbus_req;
     int ret;
-    DBusMessage *reply;
     uint16_t err_maj;
     uint32_t err_min;
     const char *err_msg = "Cannot file back end request";
     struct be_req *next_be_req = NULL;
-    dbus_bool_t dbret;
-    DBusConnection *dbus_conn;
 
     req_queue = &be_req->becli->bectx->bet_info[type].req_queue;
 
@@ -445,9 +439,9 @@ static void be_queue_next_request(struct be_req *be_req, enum bet_type type)
 
     be_queue_next_request(next_be_req, type);
 
-    reply = (DBusMessage *) next_be_req->pvt;
+    dbus_req = (struct sbus_request *) next_be_req->pvt;
 
-    if (reply) {
+    if (dbus_req) {
         /* Return a reply if one was requested
          * There may not be one if this request began
          * while we were offline
@@ -455,28 +449,13 @@ static void be_queue_next_request(struct be_req *be_req, enum bet_type type)
         err_maj = DP_ERR_FATAL;
         err_min = ret;
 
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-
-        if (!dbret) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
-            dbus_message_unref(reply);
-            goto done;
-        }
-
-        dbus_conn = sbus_get_connection(next_be_req->becli->conn);
-        if (dbus_conn == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "D-BUS not connected\n");
-            goto done;
-        }
-        dbus_connection_send(dbus_conn, reply, NULL);
-        dbus_message_unref(reply);
+        sbus_request_return_and_finish(dbus_req,
+                                       DBUS_TYPE_UINT16, &err_maj,
+                                       DBUS_TYPE_UINT32, &err_min,
+                                       DBUS_TYPE_STRING, &err_msg,
+                                       DBUS_TYPE_INVALID);
     }
 
-done:
     talloc_free(next_be_req);
 }
 
@@ -545,9 +524,7 @@ static void get_subdomains_callback(struct be_req *req,
                                     int errnum,
                                     const char *errstr)
 {
-    DBusMessage *reply;
-    DBusConnection *dbus_conn;
-    dbus_bool_t dbret;
+    struct sbus_request *dbus_req;
     dbus_uint16_t err_maj = 0;
     dbus_uint32_t err_min = 0;
     const char *err_msg = NULL;
@@ -558,9 +535,9 @@ static void get_subdomains_callback(struct be_req *req,
 
     be_queue_next_request(req, BET_SUBDOMAINS);
 
-    reply = (DBusMessage *)req->pvt;
+    dbus_req = (struct sbus_request *)req->pvt;
 
-    if (reply) {
+    if (dbus_req) {
         /* Return a reply if one was requested
          * There may not be one if this request began
          * while we were offline
@@ -578,39 +555,22 @@ static void get_subdomains_callback(struct be_req *req,
             err_msg = "OOM";
         }
 
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-
-        if (!dbret) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
-            dbus_message_unref(reply);
-            goto done;
-        }
-
-        dbus_conn = sbus_get_connection(req->becli->conn);
-        if (dbus_conn == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "D-BUS not connected\n");
-            goto done;
-        }
-        dbus_connection_send(dbus_conn, reply, NULL);
-        dbus_message_unref(reply);
+        sbus_request_return_and_finish(dbus_req,
+                                       DBUS_TYPE_UINT16, &err_maj,
+                                       DBUS_TYPE_UINT32, &err_min,
+                                       DBUS_TYPE_STRING, &err_msg,
+                                       DBUS_TYPE_INVALID);
     }
 
-done:
     talloc_free(req);
 }
 
-static int be_get_subdomains(DBusMessage *message, struct sbus_connection *conn)
+static int be_get_subdomains(struct sbus_request *dbus_req)
 {
     struct be_subdom_req *req;
     struct be_req *be_req = NULL;
     struct be_client *becli;
-    DBusMessage *reply;
     DBusError dbus_error;
-    dbus_bool_t dbret;
     void *user_data;
     dbus_bool_t force;
     char *domain_hint;
@@ -619,14 +579,14 @@ static int be_get_subdomains(DBusMessage *message, struct sbus_connection *conn)
     const char *err_msg;
     int ret;
 
-    user_data = sbus_conn_get_private_data(conn);
+    user_data = sbus_conn_get_private_data(dbus_req->conn);
     if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
     dbus_error_init(&dbus_error);
 
-    ret = dbus_message_get_args(message, &dbus_error,
+    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                 DBUS_TYPE_BOOLEAN, &force,
                                 DBUS_TYPE_STRING, &domain_hint,
                                 DBUS_TYPE_INVALID);
@@ -636,9 +596,6 @@ static int be_get_subdomains(DBusMessage *message, struct sbus_connection *conn)
         return EIO;
     }
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) return ENOMEM;
-
     /* return an error if corresponding backend target is not configured */
     if (becli->bectx->bet_info[BET_SUBDOMAINS].bet_ops == NULL) {
         DEBUG(SSSDBG_TRACE_INTERNAL, "Undefined backend target.\n");
@@ -665,7 +622,7 @@ static int be_get_subdomains(DBusMessage *message, struct sbus_connection *conn)
     /* process request */
 
     be_req = be_req_create(becli, becli, becli->bectx,
-                           get_subdomains_callback, reply);
+                           get_subdomains_callback, dbus_req);
     if (!be_req) {
         err_maj = DP_ERR_FATAL;
         err_min = ENOMEM;
@@ -710,26 +667,16 @@ immediate:
         talloc_free(be_req);
     }
 
-    if (reply) {
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
-            dbus_message_unref(reply);
-            return EIO;
-        }
+    /* send reply back */
+    sbus_request_return_and_finish(dbus_req,
+                                   DBUS_TYPE_UINT16, &err_maj,
+                                   DBUS_TYPE_UINT32, &err_min,
+                                   DBUS_TYPE_STRING, &err_msg,
+                                   DBUS_TYPE_INVALID);
 
-        if (!(err_maj == DP_ERR_FATAL && err_min == ENODEV)) {
-            DEBUG(SSSDBG_TRACE_LIBS, "Request processed. Returned %d,%d,%s\n",
-                  err_maj, err_min, err_msg);
-        }
-
-        /* send reply back */
-        sbus_conn_send_reply(conn, reply);
-        dbus_message_unref(reply);
+    if (!(err_maj == DP_ERR_FATAL && err_min == ENODEV)) {
+        DEBUG(SSSDBG_TRACE_LIBS, "Request processed. Returned %d,%d,%s\n",
+                err_maj, err_min, err_msg);
     }
 
     return EOK;
@@ -740,16 +687,14 @@ static void acctinfo_callback(struct be_req *req,
                               int errnum,
                               const char *errstr)
 {
-    DBusMessage *reply;
-    DBusConnection *dbus_conn;
-    dbus_bool_t dbret;
+    struct sbus_request *dbus_req;
     dbus_uint16_t err_maj = 0;
     dbus_uint32_t err_min = 0;
     const char *err_msg = NULL;
 
-    reply = (DBusMessage *)req->pvt;
+    dbus_req = (struct sbus_request *)req->pvt;
 
-    if (reply) {
+    if (dbus_req) {
         /* Return a reply if one was requested
          * There may not be one if this request began
          * while we were offline
@@ -768,24 +713,11 @@ static void acctinfo_callback(struct be_req *req,
             err_msg = "OOM";
         }
 
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
-            return;
-        }
-
-        dbus_conn = sbus_get_connection(req->becli->conn);
-        if (!dbus_conn) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "D-BUS not connected\n");
-            return;
-        }
-
-        dbus_connection_send(dbus_conn, reply, NULL);
-        dbus_message_unref(reply);
+        sbus_request_return_and_finish(dbus_req,
+                                       DBUS_TYPE_UINT16, &err_maj,
+                                       DBUS_TYPE_UINT32, &err_min,
+                                       DBUS_TYPE_STRING, &err_msg,
+                                       DBUS_TYPE_INVALID);
 
         DEBUG(SSSDBG_CONF_SETTINGS, "Request processed. Returned %d,%d,%s\n",
                   err_maj, err_min, err_msg);
@@ -1114,14 +1046,12 @@ errno_t be_get_account_info_recv(struct tevent_req *req,
     return EOK;
 }
 
-static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn)
+static int be_get_account_info(struct sbus_request *dbus_req)
 {
     struct be_acct_req *req;
     struct be_req *be_req;
     struct be_client *becli;
-    DBusMessage *reply;
     DBusError dbus_error;
-    dbus_bool_t dbret;
     void *user_data;
     uint32_t type;
     char *filter;
@@ -1134,14 +1064,14 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
 
     be_req = NULL;
 
-    user_data = sbus_conn_get_private_data(conn);
+    user_data = sbus_conn_get_private_data(dbus_req->conn);
     if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
     dbus_error_init(&dbus_error);
 
-    ret = dbus_message_get_args(message, &dbus_error,
+    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                 DBUS_TYPE_UINT32, &type,
                                 DBUS_TYPE_UINT32, &attr_type,
                                 DBUS_TYPE_STRING, &filter,
@@ -1156,9 +1086,6 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
     DEBUG(SSSDBG_CONF_SETTINGS,
           "Got request for [%u][%d][%s]\n", type, attr_type, filter);
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) return ENOMEM;
-
     /* If we are offline and fast reply was requested
      * return offline immediately
      */
@@ -1168,19 +1095,19 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
         err_min = EAGAIN;
         err_msg = "Fast reply - offline";
 
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) return EIO;
+        ret = sbus_request_return_and_finish(dbus_req,
+                                             DBUS_TYPE_UINT16, &err_maj,
+                                             DBUS_TYPE_UINT32, &err_min,
+                                             DBUS_TYPE_STRING, &err_msg,
+                                             DBUS_TYPE_INVALID);
+        if (ret != EOK) {
+            return ret;
+        }
 
         DEBUG(SSSDBG_CONF_SETTINGS, "Request processed. Returned %d,%d,%s\n",
                   err_maj, err_min, err_msg);
 
-        sbus_conn_send_reply(conn, reply);
-        dbus_message_unref(reply);
-        reply = NULL;
+        dbus_req = NULL;
         /* This reply will be queued and sent
          * when we reenter the mainloop.
          *
@@ -1190,7 +1117,7 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
     }
 
     be_req = be_req_create(becli, becli, becli->bectx,
-                           acctinfo_callback, reply);
+                           acctinfo_callback, dbus_req);
     if (!be_req) {
         err_maj = DP_ERR_FATAL;
         err_min = ENOMEM;
@@ -1291,20 +1218,18 @@ done:
         talloc_free(be_req);
     }
 
-    if (reply) {
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) return EIO;
+    if (dbus_req) {
+        ret = sbus_request_return_and_finish(dbus_req,
+                                             DBUS_TYPE_UINT16, &err_maj,
+                                             DBUS_TYPE_UINT32, &err_min,
+                                             DBUS_TYPE_STRING, &err_msg,
+                                             DBUS_TYPE_INVALID);
+        if (ret != EOK) {
+            return ret;
+        }
 
         DEBUG(SSSDBG_CONF_SETTINGS, "Request processed. Returned %d,%d,%s\n",
                   err_maj, err_min, err_msg);
-
-        /* send reply back */
-        sbus_conn_send_reply(conn, reply);
-        dbus_message_unref(reply);
     }
 
     return EOK;
@@ -1316,9 +1241,9 @@ static void be_pam_handler_callback(struct be_req *req,
                                     const char *errstr)
 {
     struct be_client *becli = req->becli;
+    struct sbus_request *dbus_req;
     struct pam_data *pd;
     DBusMessage *reply;
-    DBusConnection *dbus_conn;
     dbus_bool_t dbret;
     errno_t ret;
 
@@ -1353,7 +1278,14 @@ static void be_pam_handler_callback(struct be_req *req,
 
     DEBUG(SSSDBG_CONF_SETTINGS,
           "Sending result [%d][%s]\n", pd->pam_status, pd->domain);
-    reply = (DBusMessage *)req->pvt;
+    dbus_req = (struct sbus_request *)req->pvt;
+    reply = dbus_message_new_method_return(dbus_req->message);
+    if (reply == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "dbus_message_new_method_return failed, cannot send reply.\n");
+        goto done;
+    }
+
     dbret = dp_pack_pam_response(reply, pd);
     if (!dbret) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
@@ -1361,13 +1293,7 @@ static void be_pam_handler_callback(struct be_req *req,
         goto done;
     }
 
-    dbus_conn = sbus_get_connection(req->becli->conn);
-    if (!dbus_conn) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "D-BUS not connected\n");
-        goto done;
-    }
-
-    dbus_connection_send(dbus_conn, reply, NULL);
+    sbus_request_finish(dbus_req, reply);
     dbus_message_unref(reply);
 
     DEBUG(SSSDBG_CONF_SETTINGS,
@@ -1377,7 +1303,7 @@ done:
     talloc_free(req);
 }
 
-static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn)
+static int be_pam_handler(struct sbus_request *dbus_req)
 {
     DBusError dbus_error;
     DBusMessage *reply;
@@ -1388,29 +1314,21 @@ static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn)
     struct be_req *be_req = NULL;
     enum bet_type target = BET_NULL;
 
-    user_data = sbus_conn_get_private_data(conn);
+    user_data = sbus_conn_get_private_data(dbus_req->conn);
     if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "dbus_message_new_method_return failed, cannot send reply.\n");
-        return ENOMEM;
-    }
-
     be_req = be_req_create(becli, becli, becli->bectx,
-                           be_pam_handler_callback, reply);
+                           be_pam_handler_callback, dbus_req);
     if (!be_req) {
         DEBUG(SSSDBG_TRACE_LIBS, "talloc_zero failed.\n");
-        dbus_message_unref(reply);
         return ENOMEM;
     }
 
     dbus_error_init(&dbus_error);
 
-    ret = dp_unpack_pam_request(message, be_req, &pd, &dbus_error);
+    ret = dp_unpack_pam_request(dbus_req->message, be_req, &pd, &dbus_error);
     if (!ret) {
         DEBUG(SSSDBG_CRIT_FAILURE,"Failed, to parse message!\n");
         talloc_free(be_req);
@@ -1488,6 +1406,13 @@ done:
     DEBUG(SSSDBG_CONF_SETTINGS, "Sending result [%d][%s]\n",
               pd->pam_status, pd->domain);
 
+    reply = dbus_message_new_method_return(dbus_req->message);
+    if (reply == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "dbus_message_new_method_return failed, cannot send reply.\n");
+        return ENOMEM;
+    }
+
     ret = dp_pack_pam_response(reply, pd);
     if (!ret) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
@@ -1497,7 +1422,7 @@ done:
     }
 
     /* send reply back immediately */
-    sbus_conn_send_reply(conn, reply);
+    sbus_request_finish(dbus_req, reply);
     dbus_message_unref(reply);
 
     talloc_free(be_req);
@@ -1505,42 +1430,26 @@ done:
     return EOK;
 }
 
-static void be_sudo_handler_reply(struct sbus_connection *conn,
-                                  DBusMessage *reply,
+static void be_sudo_handler_reply(struct sbus_request *dbus_req,
                                   dbus_uint16_t dp_err,
                                   dbus_uint32_t dp_ret,
                                   const char *errstr)
 {
-    DBusConnection *dbus_conn = NULL;
-    dbus_bool_t dbret;
     const char *err_msg = NULL;
 
-    if (reply == NULL) {
+    if (dbus_req == NULL) {
         return;
     }
 
     err_msg = errstr ? errstr : "No errmsg set\n";
-    dbret = dbus_message_append_args(reply,
-                                     DBUS_TYPE_UINT16, &dp_err,
-                                     DBUS_TYPE_UINT32, &dp_ret,
-                                     DBUS_TYPE_STRING, &err_msg,
-                                     DBUS_TYPE_INVALID);
-    if (!dbret) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
-        return;
-    }
+    sbus_request_return_and_finish(dbus_req,
+                                   DBUS_TYPE_UINT16, &dp_err,
+                                   DBUS_TYPE_UINT32, &dp_ret,
+                                   DBUS_TYPE_STRING, &err_msg,
+                                   DBUS_TYPE_INVALID);
 
     DEBUG(SSSDBG_FUNC_DATA, "SUDO Backend returned: (%d, %d, %s)\n",
                              dp_err, dp_ret, errstr ? errstr : "<NULL>");
-
-    dbus_conn = sbus_get_connection(conn);
-    if (!dbus_conn) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "D-BUS not connected\n");
-        return;
-    }
-
-    dbus_connection_send(dbus_conn, reply, NULL);
-    dbus_message_unref(reply);
 }
 
 static void be_sudo_handler_callback(struct be_req *req,
@@ -1548,18 +1457,17 @@ static void be_sudo_handler_callback(struct be_req *req,
                                      int dp_ret,
                                      const char *errstr)
 {
-    DBusMessage *reply = NULL;
-    reply = (DBusMessage*)(req->pvt);
+    struct sbus_request *dbus_req;
+    dbus_req = (struct sbus_request *)(req->pvt);
 
-    be_sudo_handler_reply(req->becli->conn, reply, dp_err, dp_ret, errstr);
+    be_sudo_handler_reply(dbus_req, dp_err, dp_ret, errstr);
 
     talloc_free(req);
 }
 
-static int be_sudo_handler(DBusMessage *message, struct sbus_connection *conn)
+static int be_sudo_handler(struct sbus_request *dbus_req)
 {
     DBusError dbus_error;
-    DBusMessage *reply = NULL;
     DBusMessageIter iter;
     dbus_bool_t iter_next = FALSE;
     struct be_client *be_cli = NULL;
@@ -1575,7 +1483,7 @@ static int be_sudo_handler(DBusMessage *message, struct sbus_connection *conn)
 
     DEBUG(SSSDBG_TRACE_FUNC, "Entering be_sudo_handler()\n");
 
-    user_data = sbus_conn_get_private_data(conn);
+    user_data = sbus_conn_get_private_data(dbus_req->conn);
     if (user_data == NULL) {
         return EINVAL;
     }
@@ -1585,24 +1493,16 @@ static int be_sudo_handler(DBusMessage *message, struct sbus_connection *conn)
         return EINVAL;
     }
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "dbus_message_new_method_return failed, cannot send reply.\n");
-        return ENOMEM;
-    }
-
     /* create be request */
     be_req = be_req_create(be_cli, be_cli, be_cli->bectx,
-                           be_sudo_handler_callback, reply);
+                           be_sudo_handler_callback, dbus_req);
     if (be_req == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
-        dbus_message_unref(reply);
         return ENOMEM;
     }
 
     dbus_error_init(&dbus_error);
-    dbus_message_iter_init(message, &iter);
+    dbus_message_iter_init(dbus_req->message, &iter);
 
     /* get type of the request */
     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
@@ -1618,9 +1518,9 @@ static int be_sudo_handler(DBusMessage *message, struct sbus_connection *conn)
      * return offline immediately
      */
     if ((type & BE_REQ_FAST) && be_cli->bectx->offstat.offline) {
-        be_sudo_handler_reply(conn, reply, DP_ERR_OFFLINE, EAGAIN,
+        be_sudo_handler_reply(dbus_req, DP_ERR_OFFLINE, EAGAIN,
                               "Fast reply - offline");
-        reply = NULL;
+        be_req->pvt = dbus_req = NULL;
         /* This reply will be queued and sent
          * when we reenter the mainloop.
          *
@@ -1732,11 +1632,9 @@ static void be_autofs_handler_callback(struct be_req *req,
                                        int errnum,
                                        const char *errstr);
 
-static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn)
+static int be_autofs_handler(struct sbus_request *dbus_req)
 {
     DBusError dbus_error;
-    DBusMessage *reply = NULL;
-    dbus_bool_t dbret;
     struct be_client *be_cli = NULL;
     struct be_req *be_req = NULL;
     struct be_autofs_req *be_autofs_req = NULL;
@@ -1751,7 +1649,7 @@ static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn)
 
     DEBUG(SSSDBG_TRACE_FUNC, "Entering be_autofs_handler()\n");
 
-    user_data = sbus_conn_get_private_data(conn);
+    user_data = sbus_conn_get_private_data(dbus_req->conn);
     if (user_data == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get SBUS private data\n");
         return EINVAL;
@@ -1765,7 +1663,7 @@ static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn)
 
     dbus_error_init(&dbus_error);
 
-    ret = dbus_message_get_args(message, &dbus_error,
+    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                 DBUS_TYPE_UINT32, &type,
                                 DBUS_TYPE_STRING, &filter,
                                 DBUS_TYPE_INVALID);
@@ -1775,13 +1673,6 @@ static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn)
         return EIO;
     }
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "dbus_message_new_method_return failed, cannot send reply.\n");
-        return ENOMEM;
-    }
-
     /* If we are offline and fast reply was requested
      * return offline immediately
      */
@@ -1791,19 +1682,19 @@ static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn)
         err_min = EAGAIN;
         err_msg = "Fast reply - offline";
 
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) return EIO;
+        ret = sbus_request_return_and_finish(dbus_req,
+                                             DBUS_TYPE_UINT16, &err_maj,
+                                             DBUS_TYPE_UINT32, &err_min,
+                                             DBUS_TYPE_STRING, &err_msg,
+                                             DBUS_TYPE_INVALID);
+        if (ret != EOK) {
+            return ret;
+        }
 
         DEBUG(SSSDBG_TRACE_LIBS, "Request processed. Returned %d,%d,%s\n",
               err_maj, err_min, err_msg);
 
-        sbus_conn_send_reply(conn, reply);
-        dbus_message_unref(reply);
-        reply = NULL;
+        dbus_req = NULL;
         /* This reply will be queued and sent
          * when we reenter the mainloop.
          *
@@ -1830,7 +1721,7 @@ static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn)
 
     /* create be request */
     be_req = be_req_create(be_cli, be_cli, be_cli->bectx,
-                           be_autofs_handler_callback, reply);
+                           be_autofs_handler_callback, dbus_req);
     if (be_req == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
         err_maj = DP_ERR_FATAL;
@@ -1893,20 +1784,18 @@ done:
         talloc_free(be_req);
     }
 
-    if (reply) {
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) return EIO;
+    if (dbus_req) {
+        ret = sbus_request_return_and_finish(dbus_req,
+                                             DBUS_TYPE_UINT16, &err_maj,
+                                             DBUS_TYPE_UINT32, &err_min,
+                                             DBUS_TYPE_STRING, &err_msg,
+                                             DBUS_TYPE_INVALID);
+        if (ret != EOK) {
+            return ret;
+        }
 
         DEBUG(SSSDBG_TRACE_LIBS, "Request processed. Returned %d,%d,%s\n",
               err_maj, err_min, err_msg);
-
-        /* send reply back */
-        sbus_conn_send_reply(conn, reply);
-        dbus_message_unref(reply);
     }
 
     return EOK;
@@ -1917,16 +1806,14 @@ static void be_autofs_handler_callback(struct be_req *req,
                                        int errnum,
                                        const char *errstr)
 {
-    DBusMessage *reply;
-    DBusConnection *dbus_conn;
-    dbus_bool_t dbret;
+    struct sbus_request *dbus_req;
     dbus_uint16_t err_maj = 0;
     dbus_uint32_t err_min = 0;
     const char *err_msg = NULL;
 
-    reply = (DBusMessage *)req->pvt;
+    dbus_req = (struct sbus_request *)req->pvt;
 
-    if (reply) {
+    if (dbus_req) {
         /* Return a reply if one was requested
          * There may not be one if this request began
          * while we were offline
@@ -1945,24 +1832,11 @@ static void be_autofs_handler_callback(struct be_req *req,
             err_msg = "OOM";
         }
 
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
-            return;
-        }
-
-        dbus_conn = sbus_get_connection(req->becli->conn);
-        if (!dbus_conn) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "D-BUS not connected\n");
-            return;
-        }
-
-        dbus_connection_send(dbus_conn, reply, NULL);
-        dbus_message_unref(reply);
+        sbus_request_return_and_finish(dbus_req,
+                                       DBUS_TYPE_UINT16, &err_maj,
+                                       DBUS_TYPE_UINT32, &err_min,
+                                       DBUS_TYPE_STRING, &err_msg,
+                                       DBUS_TYPE_INVALID);
 
         DEBUG(SSSDBG_TRACE_LIBS,
               "Request processed. Returned %d,%d,%s\n",
@@ -1973,14 +1847,12 @@ static void be_autofs_handler_callback(struct be_req *req,
     talloc_free(req);
 }
 
-static int be_host_handler(DBusMessage *message, struct sbus_connection *conn)
+static int be_host_handler(struct sbus_request *dbus_req)
 {
     struct be_host_req *req;
     struct be_req *be_req;
     struct be_client *becli;
-    DBusMessage *reply;
     DBusError dbus_error;
-    dbus_bool_t dbret;
     void *user_data;
     uint32_t flags;
     char *filter;
@@ -1991,14 +1863,14 @@ static int be_host_handler(DBusMessage *message, struct sbus_connection *conn)
 
     be_req = NULL;
 
-    user_data = sbus_conn_get_private_data(conn);
+    user_data = sbus_conn_get_private_data(dbus_req->conn);
     if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
     dbus_error_init(&dbus_error);
 
-    ret = dbus_message_get_args(message, &dbus_error,
+    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                 DBUS_TYPE_UINT32, &flags,
                                 DBUS_TYPE_STRING, &filter,
                                 DBUS_TYPE_INVALID);
@@ -2011,9 +1883,6 @@ static int be_host_handler(DBusMessage *message, struct sbus_connection *conn)
     DEBUG(SSSDBG_TRACE_LIBS,
           "Got request for [%u][%s]\n", flags, filter);
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) return ENOMEM;
-
     /* If we are offline and fast reply was requested
      * return offline immediately
      */
@@ -2023,20 +1892,20 @@ static int be_host_handler(DBusMessage *message, struct sbus_connection *conn)
         err_min = EAGAIN;
         err_msg = "Fast reply - offline";
 
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) return EIO;
+        ret = sbus_request_return_and_finish(dbus_req,
+                                             DBUS_TYPE_UINT16, &err_maj,
+                                             DBUS_TYPE_UINT32, &err_min,
+                                             DBUS_TYPE_STRING, &err_msg,
+                                             DBUS_TYPE_INVALID);
+        if (ret != EOK) {
+            return ret;
+        }
 
         DEBUG(SSSDBG_TRACE_LIBS,
               "Request processed. Returned %d,%d,%s\n",
                err_maj, err_min, err_msg);
 
-        sbus_conn_send_reply(conn, reply);
-        dbus_message_unref(reply);
-        reply = NULL;
+        dbus_req = NULL;
         /* This reply will be queued and sent
          * when we reenter the mainloop.
          *
@@ -2046,7 +1915,7 @@ static int be_host_handler(DBusMessage *message, struct sbus_connection *conn)
     }
 
     be_req = be_req_create(becli, becli, becli->bectx,
-                           acctinfo_callback, reply);
+                           acctinfo_callback, dbus_req);
     if (!be_req) {
         err_maj = DP_ERR_FATAL;
         err_min = ENOMEM;
@@ -2114,21 +1983,19 @@ done:
         talloc_free(be_req);
     }
 
-    if (reply) {
-        dbret = dbus_message_append_args(reply,
-                                         DBUS_TYPE_UINT16, &err_maj,
-                                         DBUS_TYPE_UINT32, &err_min,
-                                         DBUS_TYPE_STRING, &err_msg,
-                                         DBUS_TYPE_INVALID);
-        if (!dbret) return EIO;
+    if (dbus_req) {
+        ret = sbus_request_return_and_finish(dbus_req,
+                                             DBUS_TYPE_UINT16, &err_maj,
+                                             DBUS_TYPE_UINT32, &err_min,
+                                             DBUS_TYPE_STRING, &err_msg,
+                                             DBUS_TYPE_INVALID);
+        if (ret != EOK) {
+            return ret;
+        }
 
         DEBUG(SSSDBG_TRACE_LIBS,
               "Request processed. Returned %d,%d,%s\n",
                err_maj, err_min, err_msg);
-
-        /* send reply back */
-        sbus_conn_send_reply(conn, reply);
-        dbus_message_unref(reply);
     }
 
     return EOK;
@@ -2163,18 +2030,19 @@ static int be_client_destructor(void *ctx)
     return 0;
 }
 
-static int client_registration(DBusMessage *message,
-                               struct sbus_connection *conn)
+static int client_registration(struct sbus_request *dbus_req)
 {
     dbus_uint16_t version = DATA_PROVIDER_VERSION;
+    struct sbus_connection *conn;
     struct be_client *becli;
-    DBusMessage *reply;
     DBusError dbus_error;
     dbus_uint16_t cli_ver;
     char *cli_name;
     dbus_bool_t dbret;
     void *data;
+    int ret;
 
+    conn = dbus_req->conn;
     data = sbus_conn_get_private_data(conn);
     becli = talloc_get_type(data, struct be_client);
     if (!becli) {
@@ -2188,7 +2056,7 @@ static int client_registration(DBusMessage *message,
 
     dbus_error_init(&dbus_error);
 
-    dbret = dbus_message_get_args(message, &dbus_error,
+    dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                   DBUS_TYPE_UINT16, &cli_ver,
                                   DBUS_TYPE_STRING, &cli_name,
                                   DBUS_TYPE_INVALID);
@@ -2221,26 +2089,14 @@ static int client_registration(DBusMessage *message,
     DEBUG(SSSDBG_CONF_SETTINGS, "Added Frontend client [%s]\n", cli_name);
 
     /* reply that all is ok */
-    reply = dbus_message_new_method_return(message);
-    if (!reply) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Dbus Out of memory!\n");
-        return ENOMEM;
-    }
-
-    dbret = dbus_message_append_args(reply,
-                                     DBUS_TYPE_UINT16, &version,
-                                     DBUS_TYPE_INVALID);
-    if (!dbret) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to build dbus reply\n");
-        dbus_message_unref(reply);
+    ret = sbus_request_return_and_finish(dbus_req,
+                                         DBUS_TYPE_UINT16, &version,
+                                         DBUS_TYPE_INVALID);
+    if (ret != EOK) {
         sbus_disconnect(conn);
-        return EIO;
+        return ret;
     }
 
-    /* send reply back */
-    sbus_conn_send_reply(conn, reply);
-    dbus_message_unref(reply);
-
     becli->initialized = true;
     return EOK;
 }
@@ -3023,45 +2879,41 @@ int main(int argc, const char *argv[])
 }
 #endif
 
-static int data_provider_res_init(DBusMessage *message,
-                                  struct sbus_connection *conn)
+static int data_provider_res_init(struct sbus_request *dbus_req)
 {
     struct be_ctx *be_ctx;
-    be_ctx = talloc_get_type(sbus_conn_get_private_data(conn), struct be_ctx);
+    be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn), struct be_ctx);
 
     resolv_reread_configuration(be_ctx->be_res->resolv);
     check_if_online(be_ctx);
 
-    return monitor_common_res_init(message, conn);
+    return monitor_common_res_init(dbus_req);
 }
 
-static int data_provider_go_offline(DBusMessage *message,
-                                    struct sbus_connection *conn)
+static int data_provider_go_offline(struct sbus_request *dbus_req)
 {
     struct be_ctx *be_ctx;
-    be_ctx = talloc_get_type(sbus_conn_get_private_data(conn), struct be_ctx);
+    be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn), struct be_ctx);
     be_mark_offline(be_ctx);
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-static int data_provider_reset_offline(DBusMessage *message,
-                                       struct sbus_connection *conn)
+static int data_provider_reset_offline(struct sbus_request *dbus_req)
 {
     struct be_ctx *be_ctx;
-    be_ctx = talloc_get_type(sbus_conn_get_private_data(conn), struct be_ctx);
+    be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn), struct be_ctx);
     check_if_online(be_ctx);
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-static int data_provider_logrotate(DBusMessage *message,
-                                struct sbus_connection *conn)
+static int data_provider_logrotate(struct sbus_request *dbus_req)
 {
     errno_t ret;
-    struct be_ctx *be_ctx = talloc_get_type(sbus_conn_get_private_data(conn),
+    struct be_ctx *be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
                                             struct be_ctx);
 
     ret = monitor_common_rotate_logs(be_ctx->cdb, be_ctx->conf_path);
     if (ret != EOK) return ret;
 
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c
index 46b55b9b84a232db752360466933679ebfc3583f..44d4fd6623e2ab4dc8dc6c7c7caf5d3029ec25b5 100644
--- a/src/providers/proxy/proxy_child.c
+++ b/src/providers/proxy/proxy_child.c
@@ -47,7 +47,7 @@
 
 #include "providers/dp_backend.h"
 
-static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn);
+static int pc_pam_handler(struct sbus_request *dbus_req);
 
 struct data_provider_iface pc_methods = {
     { &data_provider_iface_meta, 0 },
@@ -310,7 +310,7 @@ fail:
     return ret;
 }
 
-static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn)
+static int pc_pam_handler(struct sbus_request *dbus_req)
 {
     DBusError dbus_error;
     DBusMessage *reply;
@@ -319,7 +319,7 @@ static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn)
     void *user_data;
     struct pam_data *pd = NULL;
 
-    user_data = sbus_conn_get_private_data(conn);
+    user_data = sbus_conn_get_private_data(dbus_req->conn);
     if (!user_data) {
         ret = EINVAL;
         goto done;
@@ -330,7 +330,7 @@ static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn)
         goto done;
     }
 
-    reply = dbus_message_new_method_return(message);
+    reply = dbus_message_new_method_return(dbus_req->message);
     if (!reply) {
         DEBUG(SSSDBG_CRIT_FAILURE, "dbus_message_new_method_return failed, "
                   "cannot send reply.\n");
@@ -340,7 +340,7 @@ static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn)
 
     dbus_error_init(&dbus_error);
 
-    ret = dp_unpack_pam_request(message, pc_ctx, &pd, &dbus_error);
+    ret = dp_unpack_pam_request(dbus_req->message, pc_ctx, &pd, &dbus_error);
     if (!ret) {
         DEBUG(SSSDBG_CRIT_FAILURE,"Failed, to parse message!\n");
         ret = EIO;
@@ -375,14 +375,14 @@ static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn)
         goto done;
     }
 
-    sbus_conn_send_reply(conn, reply);
+    ret = sbus_request_finish(dbus_req, reply);
     dbus_message_unref(reply);
     talloc_free(pd);
 
     /* We'll return the message and let the
      * parent process kill us.
      */
-    return EOK;
+    return ret;
 
 done:
     exit(ret);
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
index 60ae4a950fd18648d13b7fe50ef73d9a398ad8d5..70fe337cde7925311295f0b682860aa3d5de0a94 100644
--- a/src/providers/proxy/proxy_init.c
+++ b/src/providers/proxy/proxy_init.c
@@ -27,8 +27,7 @@
 #include "util/sss_format.h"
 #include "providers/proxy/proxy.h"
 
-static int client_registration(DBusMessage *message,
-                               struct sbus_connection *conn);
+static int client_registration(struct sbus_request *dbus_req);
 
 static struct data_provider_iface proxy_methods = {
     { &data_provider_iface_meta, 0 },
@@ -395,12 +394,11 @@ static void init_timeout(struct tevent_context *ev,
      */
 }
 
-static int client_registration(DBusMessage *message,
-                               struct sbus_connection *conn)
+static int client_registration(struct sbus_request *dbus_req)
 {
     dbus_uint16_t version = DATA_PROVIDER_VERSION;
+    struct sbus_connection *conn;
     struct proxy_client *proxy_cli;
-    DBusMessage *reply;
     DBusError dbus_error;
     dbus_uint16_t cli_ver;
     uint32_t cli_id;
@@ -412,7 +410,9 @@ static int client_registration(DBusMessage *message,
     struct tevent_req *req;
     struct proxy_child_ctx *child_ctx;
     struct pc_init_ctx *init_ctx;
+    int ret;
 
+    conn = dbus_req->conn;
     data = sbus_conn_get_private_data(conn);
     proxy_cli = talloc_get_type(data, struct proxy_client);
     if (!proxy_cli) {
@@ -427,7 +427,7 @@ static int client_registration(DBusMessage *message,
 
     dbus_error_init(&dbus_error);
 
-    dbret = dbus_message_get_args(message, &dbus_error,
+    dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                   DBUS_TYPE_UINT16, &cli_ver,
                                   DBUS_TYPE_UINT32, &cli_id,
                                   DBUS_TYPE_INVALID);
@@ -453,31 +453,19 @@ static int client_registration(DBusMessage *message,
     }
 
     /* reply that all is ok */
-    reply = dbus_message_new_method_return(message);
-    if (!reply) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Dbus Out of memory!\n");
-        return ENOMEM;
-    }
-
-    dbret = dbus_message_append_args(reply,
-                                     DBUS_TYPE_UINT16, &version,
-                                     DBUS_TYPE_INVALID);
-    if (!dbret) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to build dbus reply\n");
-        dbus_message_unref(reply);
+    ret = sbus_request_return_and_finish(dbus_req,
+                                         DBUS_TYPE_UINT16, &version,
+                                         DBUS_TYPE_INVALID);
+    if (ret != EOK) {
         sbus_disconnect(conn);
-        return EIO;
+        return ret;
     }
 
-    /* send reply back */
-    sbus_conn_send_reply(conn, reply);
-    dbus_message_unref(reply);
-
     hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value);
     if (hret != HASH_SUCCESS) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Hash error [%d][%s]\n", hret, hash_error_string(hret));
-        sbus_disconnect(conn);
+        sbus_disconnect(dbus_req->conn);
     }
 
     /* Signal that the child is up and ready to receive the request */
@@ -496,7 +484,7 @@ static int client_registration(DBusMessage *message,
     }
 
     init_ctx = tevent_req_data(child_ctx->init_req, struct pc_init_ctx);
-    init_ctx->conn = conn;
+    init_ctx->conn = dbus_req->conn;
     tevent_req_done(child_ctx->init_req);
     child_ctx->init_req = NULL;
 
diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
index 5ce9ae0236d61b6b643cbc0682dc4bb53774b87f..b447a063448e420dac0b0ad6e9210a26b96d9c79 100644
--- a/src/responder/autofs/autofssrv.c
+++ b/src/responder/autofs/autofssrv.c
@@ -29,8 +29,7 @@
 #include "providers/data_provider.h"
 #include "responder/autofs/autofs_private.h"
 
-static int autofs_clean_hash_table(DBusMessage *message,
-                                   struct sbus_connection *conn);
+static int autofs_clean_hash_table(struct sbus_request *dbus_req);
 
 struct mon_cli_iface monitor_autofs_methods = {
     { &mon_cli_iface_meta, 0 },
@@ -112,10 +111,9 @@ autofs_dp_reconnect_init(struct sbus_connection *conn,
                                  be_conn->domain->name);
 }
 
-static int autofs_clean_hash_table(DBusMessage *message,
-                                   struct sbus_connection *conn)
+static int autofs_clean_hash_table(struct sbus_request *dbus_req)
 {
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
                                             struct resp_ctx);
     struct autofs_ctx *actx =
             talloc_get_type(rctx->pvt_ctx, struct autofs_ctx);
@@ -127,7 +125,7 @@ static int autofs_clean_hash_table(DBusMessage *message,
         return ret;
     }
 
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
 static int
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 5331d5b759059c1a78f3ce70adf4d5a309079efb..9d7cf3b54cefe339dcafce9a54b5e085d37212ae 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -214,8 +214,7 @@ struct dp_callback_ctx {
 
 void handle_requests_after_reconnect(struct resp_ctx *rctx);
 
-int responder_logrotate(DBusMessage *message,
-                        struct sbus_connection *conn);
+int responder_logrotate(struct sbus_request *dbus_req);
 
 /* Each responder-specific request must create a constructor
  * function that creates a DBus Message that would be sent to
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 37c2ebe3a550ae9c787c82f4556eec32ed374edf..dabf5c053904d0e3df84b849bd0033bc78c1392e 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -989,17 +989,16 @@ done:
     return ret;
 }
 
-int responder_logrotate(DBusMessage *message,
-                        struct sbus_connection *conn)
+int responder_logrotate(struct sbus_request *dbus_req)
 {
     errno_t ret;
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
                                             struct resp_ctx);
 
     ret = monitor_common_rotate_logs(rctx->cdb, rctx->confdb_service_path);
     if (ret != EOK) return ret;
 
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
 void responder_set_fd_limit(rlim_t fd_limit)
diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
index 05408db59fad12c4475ef796f8a4b6975ec50b6d..db4e18762c05ed5c36fbe18da3c6e5a80d8083ce 100644
--- a/src/responder/nss/nsssrv.c
+++ b/src/responder/nss/nsssrv.c
@@ -55,10 +55,8 @@
 #define SHELL_REALLOC_INCREMENT 5
 #define SHELL_REALLOC_MAX       50
 
-static int nss_clear_memcache(DBusMessage *message,
-                              struct sbus_connection *conn);
-static int nss_clear_netgroup_hash_table(DBusMessage *message,
-                                         struct sbus_connection *conn);
+static int nss_clear_memcache(struct sbus_request *dbus_req);
+static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req);
 
 struct mon_cli_iface monitor_nss_methods = {
     { &mon_cli_iface_meta, 0 },
@@ -75,15 +73,14 @@ struct mon_cli_iface monitor_nss_methods = {
 struct sbus_interface monitor_nss_interface = {
     MONITOR_PATH,
     &monitor_nss_methods.vtable,
-    NULL
+    NULL,
 };
 
-static int nss_clear_memcache(DBusMessage *message,
-                              struct sbus_connection *conn)
+static int nss_clear_memcache(struct sbus_request *dbus_req)
 {
     errno_t ret;
     int memcache_timeout;
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
                                             struct resp_ctx);
     struct nss_ctx *nctx = (struct nss_ctx*) rctx->pvt_ctx;
 
@@ -134,14 +131,13 @@ static int nss_clear_memcache(DBusMessage *message,
     }
 
 done:
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-static int nss_clear_netgroup_hash_table(DBusMessage *message,
-                                         struct sbus_connection *conn)
+static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req)
 {
     errno_t ret;
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
                                             struct resp_ctx);
     struct nss_ctx *nctx = (struct nss_ctx*) rctx->pvt_ctx;
 
@@ -152,7 +148,7 @@ static int nss_clear_netgroup_hash_table(DBusMessage *message,
         return ret;
     }
 
-    return monitor_common_pong(message, conn);
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
 static errno_t nss_get_etc_shells(TALLOC_CTX *mem_ctx, char ***_shells)
@@ -308,10 +304,9 @@ done:
     return ret;
 }
 
-static int nss_update_memcache(DBusMessage *message,
-                               struct sbus_connection *conn)
+static int nss_update_memcache(struct sbus_request *dbus_req)
 {
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
                                             struct resp_ctx);
     struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
 
@@ -321,15 +316,13 @@ static int nss_update_memcache(DBusMessage *message,
     return EOK;
 }
 
-static int nss_memcache_initgr_check(DBusMessage *message,
-                                     struct sbus_connection *conn)
+static int nss_memcache_initgr_check(struct sbus_request *dbus_req)
 {
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
                                             struct resp_ctx);
     struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
     DBusError dbus_error;
     dbus_bool_t dbret;
-    DBusMessage *reply;
     char *user;
     char *domain;
     uint32_t *groups;
@@ -337,7 +330,7 @@ static int nss_memcache_initgr_check(DBusMessage *message,
 
     dbus_error_init(&dbus_error);
 
-    dbret = dbus_message_get_args(message, &dbus_error,
+    dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
                                   DBUS_TYPE_STRING, &user,
                                   DBUS_TYPE_STRING, &domain,
                                   DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
@@ -357,20 +350,7 @@ static int nss_memcache_initgr_check(DBusMessage *message,
 
     nss_update_initgr_memcache(nctx, user, domain, gnum, groups);
 
-    reply = dbus_message_new_method_return(message);
-    if (!reply) return ENOMEM;
-
-    dbret = dbus_message_append_args(reply, DBUS_TYPE_INVALID);
-    if (!dbret) {
-        dbus_message_unref(reply);
-        return EIO;
-    }
-
-    /* send reply back */
-    sbus_conn_send_reply(conn, reply);
-    dbus_message_unref(reply);
-
-    return EOK;
+    return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
 static struct data_provider_rev_iface nss_dp_methods = {
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index 3c99b3100e77a259fbdd7f209d2049b855b4bca9..dcb66907916606baede8a9744d775d7cce8a6e68 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -24,9 +24,11 @@
 
 struct sbus_connection;
 
-#include "dbus/dbus.h"
+struct sbus_request;
 
-typedef int (*sbus_msg_handler_fn)(DBusMessage *, struct sbus_connection *);
+#include <dbus/dbus.h>
+
+typedef int (*sbus_msg_handler_fn)(struct sbus_request *dbus_req);
 
 /*
  * sbus_conn_destructor_fn
@@ -170,4 +172,78 @@ int sbus_conn_send(struct sbus_connection *conn,
 void sbus_conn_send_reply(struct sbus_connection *conn,
                           DBusMessage *reply);
 
+/*
+ * This structure is passed to all dbus method and property
+ * handlers. It is a talloc context which will be valid until
+ * the request is completed with either the sbus_request_complete()
+ * or sbus_request_fail() functions.
+ */
+struct sbus_request {
+    struct sbus_connection *conn;
+    DBusMessage *message;
+    struct sbus_interface *intf;
+    const struct sbus_method_meta *method;
+};
+
+/*
+ * Complete a DBus request, and free the @dbus_req context. The @dbus_req
+ * and associated talloc context are no longer valid after this function
+ * returns.
+ *
+ * If @reply is non-NULL then the reply is sent to the caller. Not sending
+ * a reply when the caller is expecting one is fairly rude behavior.
+ *
+ * The return value is useful for logging, but not much else. In particular
+ * even if this function return !EOK, @dbus_req is still unusable after this
+ * function returns.
+ */
+int sbus_request_finish(struct sbus_request *dbus_req,
+                        DBusMessage *reply);
+
+/*
+ * Return a reply for a DBus method call request. The variable
+ * arguments are (unfortunately) formatted exactly the same as those of the
+ * dbus_message_append_args() function. Documented here:
+ *
+ * http://dbus.freedesktop.org/doc/api/html/group__DBusMessage.html
+ *
+ * Important: don't pass int or bool or such types as
+ * values to this function. That's not portable. Use actual dbus types.
+ * You must also pass pointers as the values:
+ *
+ *    dbus_bool_t val1 = TRUE;
+ *    dbus_int32_t val2 = 5;
+ *    ret = sbus_request_finish(dbus_req,
+ *                              DBUS_TYPE_BOOLEAN, &val1,
+ *                              DBUS_TYPE_INT32, &val2,
+ *                              DBUS_TYPE_INVALID);
+ *
+ * To pass arrays to this function, use the following syntax. Never
+ * pass actual C arrays with [] syntax to this function. The C standard is
+ * rather vague with C arrays and varargs, and it just plain doesn't work.
+ *
+ *    const char *array[] = { "one", "two", "three" };
+ *    int count = 3; // yes, a plain int
+ *    const char **ptr = array;
+ *    ret = sbus_request_finish(dbus_req,
+ *                              DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &ptr, 3,
+ *                              DBUS_TYPE_INVALID);
+ *
+ * The @dbus_req and associated talloc context are no longer valid after this
+ * function returns, even if this function returns an error code.
+ */
+int sbus_request_return_and_finish(struct sbus_request *dbus_req,
+                                   int first_arg_type,
+                                   ...);
+
+/*
+ * Return an error for a DBus method call request. The @error is a normal
+ * DBusError.
+ *
+ * The @dbus_req and associated talloc context are no longer valid after this
+ * function returns, even if this function returns an error code.
+ */
+int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
+                                 const DBusError *error);
+
 #endif /* _SSSD_DBUS_H_*/
diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
index e3f5e163df1609b1d9fea3540d3eff6c07ea868d..6535bc90e66e81d5c30ccd9fc598ca9b64a498be 100644
--- a/src/sbus/sssd_dbus_connection.c
+++ b/src/sbus/sssd_dbus_connection.c
@@ -415,7 +415,9 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
     DBusMessage *reply = NULL;
     const struct sbus_method_meta *method;
     const struct sbus_interface_meta *interface;
-    sbus_msg_handler_fn handler_fn;
+    struct sbus_request *dbus_req = NULL;
+    sbus_msg_handler_fn handler_fn = NULL;
+    DBusHandlerResult result;
     int ret;
 
     if (!user_data) {
@@ -435,10 +437,11 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
     if (strcmp(path, intf_p->intf->path) != 0)
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
+    result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
     /* Validate the method interface */
     interface = intf_p->intf->vtable->meta;
     if (strcmp(msg_interface, interface->name) == 0) {
-        handler_fn = NULL;
         method = sbus_meta_find_method(interface, msg_method);
         if (method && method->vtable_offset)
             handler_fn = VTABLE_FUNC(intf_p->intf->vtable, method->vtable_offset);
@@ -450,6 +453,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
             reply = dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL);
             sbus_conn_send_reply(intf_p->conn, reply);
             dbus_message_unref(reply);
+            result = DBUS_HANDLER_RESULT_HANDLED;
 
         } else if (!handler_fn) {
             /* Reply DBUS_ERROR_NOT_SUPPORTED */
@@ -458,11 +462,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
             reply = dbus_message_new_error(message, DBUS_ERROR_NOT_SUPPORTED, NULL);
             sbus_conn_send_reply(intf_p->conn, reply);
             dbus_message_unref(reply);
-
-        } else {
-            ret = handler_fn(message, intf_p->conn);
-            if (ret != EOK)
-                return sbus_reply_internal_error(message, intf_p->conn);
+            result = DBUS_HANDLER_RESULT_HANDLED;
         }
     }
     else {
@@ -472,21 +472,28 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
         if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
             strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0)
         {
-            if (intf_p->intf->introspect_fn) {
-                /* If we have been asked for introspection data and we have
-                 * an introspection function registered, user that.
-                 */
-                ret = intf_p->intf->introspect_fn(message, intf_p->conn);
-                if (ret != EOK) {
-                    return sbus_reply_internal_error(message, intf_p->conn);
-                }
-            }
+            handler_fn = intf_p->intf->introspect_fn;
         }
-        else
-            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
-    return DBUS_HANDLER_RESULT_HANDLED;
+    if (handler_fn) {
+        dbus_req = sbus_new_request(intf_p->conn, intf_p->intf, message);
+        if (!dbus_req) {
+            ret = ENOMEM;
+        } else {
+            dbus_req->method = method;
+            ret = handler_fn(dbus_req);
+        }
+        if (ret != EOK) {
+            if (dbus_req)
+                talloc_free(dbus_req);
+            result = sbus_reply_internal_error(message, intf_p->conn);
+        } else {
+            result = DBUS_HANDLER_RESULT_HANDLED;
+        }
+    }
+
+    return result;
 }
 
 /* Adds a new D-BUS path message handler to the connection
@@ -785,4 +792,3 @@ void sbus_conn_send_reply(struct sbus_connection *conn, DBusMessage *reply)
 {
     dbus_connection_send(conn->dbus.conn, reply, NULL);
 }
-
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index c62e0e3f60772dabc0a486e02eabf9eb017e12e8..eca5c8380493754bb6fd55ef47f1740c5f095021 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -96,4 +96,10 @@ dbus_bool_t sbus_add_timeout(DBusTimeout *dbus_timeout, void *data);
 void sbus_toggle_timeout(DBusTimeout *dbus_timeout, void *data);
 void sbus_remove_timeout(DBusTimeout *dbus_timeout, void *data);
 
+/* =Requests============================================================== */
+
+struct sbus_request *
+sbus_new_request(struct sbus_connection *conn, struct sbus_interface *intf,
+                 DBusMessage *message);
+
 #endif /* _SSSD_DBUS_PRIVATE_H_ */
diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c
new file mode 100644
index 0000000000000000000000000000000000000000..973089c4bbc5d766edfe5792a366d0548c3c3855
--- /dev/null
+++ b/src/sbus/sssd_dbus_request.c
@@ -0,0 +1,112 @@
+/*
+    Authors:
+        Stef Walter <stefw at redhat.com>
+
+    Copyright (C) 2014 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 "util/util.h"
+#include "sbus/sssd_dbus.h"
+
+#include <sys/time.h>
+#include <dbus/dbus.h>
+
+static int sbus_request_destructor(struct sbus_request *dbus_req)
+{
+    dbus_message_unref(dbus_req->message);
+    return 0;
+}
+
+struct sbus_request *
+sbus_new_request(struct sbus_connection *conn,
+                 struct sbus_interface *intf,
+                 DBusMessage *message)
+{
+    struct sbus_request *dbus_req;
+
+    dbus_req = talloc_zero(conn, struct sbus_request);
+    if (!dbus_req) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory allocating DBus request\n");
+        return NULL;
+    }
+
+    dbus_req->intf = intf;
+    dbus_req->conn = conn;
+    dbus_req->message = dbus_message_ref(message);
+    talloc_set_destructor(dbus_req, sbus_request_destructor);
+
+    return dbus_req;
+}
+
+int sbus_request_finish(struct sbus_request *dbus_req,
+                        DBusMessage *reply)
+{
+    if (reply) {
+        sbus_conn_send_reply(dbus_req->conn, reply);
+    }
+    return talloc_free(dbus_req);
+}
+
+int sbus_request_return_and_finish(struct sbus_request *dbus_req,
+                                   int first_arg_type,
+                                   ...)
+{
+    DBusMessage *reply;
+    dbus_bool_t dbret;
+    va_list va;
+    int ret;
+
+    reply = dbus_message_new_method_return(dbus_req->message);
+    if (!reply) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory allocating DBus message\n");
+        sbus_request_finish(dbus_req, NULL);
+        return ENOMEM;
+    }
+
+    va_start(va, first_arg_type);
+    dbret = dbus_message_append_args_valist(reply, first_arg_type, va);
+    va_end(va);
+
+    if (dbret) {
+        ret = sbus_request_finish(dbus_req, reply);
+
+    } else {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't build DBus message\n");
+        sbus_request_finish(dbus_req, NULL);
+        ret = EINVAL;
+    }
+
+    dbus_message_unref(reply);
+    return ret;
+}
+
+int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
+                                 const DBusError *error)
+{
+    DBusMessage *reply;
+    int ret;
+
+    reply = dbus_message_new_error(dbus_req->message, error->name, error->message);
+    if (!reply) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory allocating DBus message\n");
+        sbus_request_finish(dbus_req, NULL);
+        return ENOMEM;
+    }
+
+    ret = sbus_request_finish(dbus_req, reply);
+    dbus_message_unref(reply);
+    return ret;
+}
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index 7386756cd1ed37fe5362634e9432bba5893d6ee3..146e18a850ad8dc322a379bdbb5c70ec95153277 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -113,14 +113,14 @@ START_TEST(test_signals)
 END_TEST
 
 static int
-mock_move_universe(DBusMessage *msg, struct sbus_connection *conn)
+mock_move_universe(struct sbus_request *dbus_req)
 {
     /* not called */
     return 0;
 }
 
 static int
-mock_crash_now(DBusMessage *msg, struct sbus_connection *conn)
+mock_crash_now(struct sbus_request *dbus_req)
 {
     /* not called */
     return 0;
-- 
1.9.0

-------------- next part --------------
>From c83158105113c2f1f51116561227078689ec35f0 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at redhat.com>
Date: Tue, 18 Feb 2014 14:32:54 +0100
Subject: [PATCH 2/5] sbus: Refactor how we export DBus interfaces
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Most importantly, stop using per connection private data. This doesn't
scale when you have more than one thing exporting or exported on a
connection.

Remove struct sbus_interface and expand sbus_conn_add_interface()
function. Remove various struct sbus_interface args to connection
initialization functions and make callers use sbus_conn_add_interface()
directly. The old method was optimized for exporting one interface
on a connection. We'll have connections that export zero, one or more
interfaces.

To export an interface on a DBus server, call sbus_conn_add_interface()
from within the sbus_server_conn_init_fn. To export an interface on
a DBus client, call sbus_conn_add_interface() after sbus_new_connection()
returns.

As before struct sbus_interface represents an object exported via DBus.
However it is now talloc allocated. One can set instance data on the
struct sbus_interface. This instance data is passed to the various
handlers and used in their implementation.

However, we now have type safe interface exporting in the various
high level sss_process_init() sss_monitor_init() and so on.

Introspection support was not in use, and is now gone until we
implement it using the metadata (future patch).

Reviewed-by: Jakub Hrozek <jhrozek at redhat.com>
Reviewed-by: Pavel Březina <pbrezina at redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn at redhat.com>
(cherry picked from commit 07e941c1bbdc752142bbd3b838c540bc7ecd0ed7)
---
 src/monitor/monitor.c                   |  23 +++----
 src/monitor/monitor_interfaces.h        |   6 +-
 src/monitor/monitor_sbus.c              |  22 +++++--
 src/providers/data_provider_be.c        | 107 +++++++++++---------------------
 src/providers/proxy/proxy_child.c       |  32 +++++-----
 src/providers/proxy/proxy_init.c        |  22 +++----
 src/responder/autofs/autofssrv.c        |  23 ++-----
 src/responder/common/responder.h        |  18 ++++--
 src/responder/common/responder_common.c |  27 +++++---
 src/responder/nss/nsssrv.c              |  41 ++++--------
 src/responder/pac/pacsrv.c              |  17 +----
 src/responder/pam/pamsrv.c              |  17 +----
 src/responder/ssh/sshsrv.c              |  16 +----
 src/responder/sudo/sudosrv.c            |  16 +----
 src/sbus/sbus_client.c                  |  11 +---
 src/sbus/sbus_client.h                  |   5 +-
 src/sbus/sssd_dbus.h                    |  32 ++++++----
 src/sbus/sssd_dbus_connection.c         |  96 +++++++++-------------------
 src/sbus/sssd_dbus_private.h            |   4 --
 src/sbus/sssd_dbus_server.c             |   8 +--
 src/tests/sbus_codegen_tests.c          |   4 +-
 21 files changed, 199 insertions(+), 348 deletions(-)

diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 956e754254af37cb9ccb0df58ddd3d4269daab1d..aaf3e56f08fff8a666f522269758634b064ada0e 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -219,7 +219,7 @@ static void network_status_change_cb(void *cb_data)
 
 /* dbus_get_monitor_version
  * Return the monitor version over D-BUS */
-static int get_monitor_version(struct sbus_request *dbus_req)
+static int get_monitor_version(struct sbus_request *dbus_req, void *data)
 {
     dbus_uint16_t version = MONITOR_VERSION;
 
@@ -238,19 +238,17 @@ static int add_svc_conn_spy(struct mt_svc *svc);
 
 /* registers a new client.
  * if operation is successful also sends back the Monitor version */
-static int client_registration(struct sbus_request *dbus_req)
+static int client_registration(struct sbus_request *dbus_req, void *data)
 {
     dbus_uint16_t version = MONITOR_VERSION;
     struct mon_init_conn *mini;
     struct mt_svc *svc;
-    void *data;
     DBusError dbus_error;
     dbus_uint16_t svc_ver;
     char *svc_name;
     dbus_bool_t dbret;
     int ret;
 
-    data = sbus_conn_get_private_data(dbus_req->conn);
     mini = talloc_get_type(data, struct mon_init_conn);
     if (!mini) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
@@ -505,12 +503,6 @@ struct mon_srv_iface monitor_methods = {
     .RegisterService = client_registration,
 };
 
-struct sbus_interface monitor_server_interface = {
-    MON_SRV_PATH,
-    &monitor_methods.vtable,
-    NULL
-};
-
 /* monitor_dbus_init
  * Set up the monitor service as a D-BUS Server */
 static int monitor_dbus_init(struct mt_ctx *ctx)
@@ -523,8 +515,7 @@ static int monitor_dbus_init(struct mt_ctx *ctx)
         return ret;
     }
 
-    ret = sbus_new_server(ctx, ctx->ev,
-                          monitor_address, &monitor_server_interface,
+    ret = sbus_new_server(ctx, ctx->ev, monitor_address,
                           false, &ctx->sbus_srv, monitor_service_init, ctx);
 
     talloc_free(monitor_address);
@@ -2294,6 +2285,7 @@ static void init_timeout(struct tevent_context *ev,
  */
 static int monitor_service_init(struct sbus_connection *conn, void *data)
 {
+    struct sbus_interface *intf;
     struct mt_ctx *ctx;
     struct mon_init_conn *mini;
     struct timeval tv;
@@ -2321,9 +2313,12 @@ static int monitor_service_init(struct sbus_connection *conn, void *data)
         return ENOMEM;
     }
 
-    sbus_conn_set_private_data(conn, mini);
+    intf = sbus_new_interface(conn, MON_SRV_PATH, &monitor_methods.vtable, mini);
+    if (!intf) {
+        return ENOMEM;
+    }
 
-    return EOK;
+    return sbus_conn_add_interface(conn, intf);
 }
 
 /* service_send_ping
diff --git a/src/monitor/monitor_interfaces.h b/src/monitor/monitor_interfaces.h
index 2970251df94e75e5b1f5f746792a6eaf11f9577d..c015fbc66cf561aa85afa668768a14ecced3f0f9 100644
--- a/src/monitor/monitor_interfaces.h
+++ b/src/monitor/monitor_interfaces.h
@@ -38,14 +38,14 @@
 int monitor_get_sbus_address(TALLOC_CTX *mem_ctx, char **address);
 int monitor_common_send_id(struct sbus_connection *conn,
                            const char *name, uint16_t version);
-int monitor_common_pong(struct sbus_request *dbus_req);
-int monitor_common_res_init(struct sbus_request *dbus_req);
+int monitor_common_pong(struct sbus_request *dbus_req, void *data);
+int monitor_common_res_init(struct sbus_request *dbus_req, void *data);
 int monitor_common_rotate_logs(struct confdb_ctx *confdb,
                                const char *conf_entry);
 
 errno_t sss_monitor_init(TALLOC_CTX *mem_ctx,
                          struct tevent_context *ev,
-                         struct sbus_interface *intf,
+                         struct mon_cli_iface *mon_iface,
                          const char *svc_name,
                          uint16_t svc_version,
                          void *pvt,
diff --git a/src/monitor/monitor_sbus.c b/src/monitor/monitor_sbus.c
index 92d483233bd1cae45949dad1cd84b596cb099cec..544407ca207c89ad9a26c4efe18512f7fb59c9a4 100644
--- a/src/monitor/monitor_sbus.c
+++ b/src/monitor/monitor_sbus.c
@@ -144,12 +144,12 @@ int monitor_common_send_id(struct sbus_connection *conn,
     return retval;
 }
 
-int monitor_common_pong(struct sbus_request *dbus_req)
+int monitor_common_pong(struct sbus_request *dbus_req, void *data)
 {
     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-int monitor_common_res_init(struct sbus_request *dbus_req)
+int monitor_common_res_init(struct sbus_request *dbus_req, void *data)
 {
     int ret;
 
@@ -198,7 +198,7 @@ errno_t monitor_common_rotate_logs(struct confdb_ctx *confdb,
 
 errno_t sss_monitor_init(TALLOC_CTX *mem_ctx,
                          struct tevent_context *ev,
-                         struct sbus_interface *intf,
+                         struct mon_cli_iface *mon_iface,
                          const char *svc_name,
                          uint16_t svc_version,
                          void *pvt,
@@ -206,6 +206,7 @@ errno_t sss_monitor_init(TALLOC_CTX *mem_ctx,
 {
     errno_t ret;
     char *sbus_address;
+    struct sbus_interface *intf;
     struct sbus_connection *conn;
 
     /* Set up SBUS connection to the monitor */
@@ -215,9 +216,7 @@ errno_t sss_monitor_init(TALLOC_CTX *mem_ctx,
         return ret;
     }
 
-    ret = sbus_client_init(mem_ctx, ev, sbus_address,
-                           intf, &conn,
-                           NULL, pvt);
+    ret = sbus_client_init(mem_ctx, ev, sbus_address, &conn);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to connect to monitor services.\n");
         talloc_free(sbus_address);
@@ -225,6 +224,17 @@ errno_t sss_monitor_init(TALLOC_CTX *mem_ctx,
     }
     talloc_free(sbus_address);
 
+    intf = sbus_new_interface(mem_ctx, MONITOR_PATH, &mon_iface->vtable, pvt);
+    if (!intf) {
+        ret = ENOMEM;
+    } else {
+        ret = sbus_conn_add_interface(conn, intf);
+    }
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export monitor client.\n");
+        return ret;
+    }
+
     /* Identify ourselves to the monitor */
     ret = monitor_common_send_id(conn, svc_name, svc_version);
     if (ret != EOK) {
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index ea3939f7e99d15da50ddc697b58217980dd7712b..3c2dda230dee02f2bfa44e7d96eb63d8c5d308b4 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -54,10 +54,10 @@
 #define ACCESS_DENY "deny"
 #define NO_PROVIDER "none"
 
-static int data_provider_res_init(struct sbus_request *dbus_req);
-static int data_provider_go_offline(struct sbus_request *dbus_req);
-static int data_provider_reset_offline(struct sbus_request *dbus_req);
-static int data_provider_logrotate(struct sbus_request *dbus_req);
+static int data_provider_res_init(struct sbus_request *dbus_req, void *data);
+static int data_provider_go_offline(struct sbus_request *dbus_req, void *data);
+static int data_provider_reset_offline(struct sbus_request *dbus_req, void *data);
+static int data_provider_logrotate(struct sbus_request *dbus_req, void *data);
 
 struct mon_cli_iface monitor_be_methods = {
     { &mon_cli_iface_meta, 0 },
@@ -71,19 +71,13 @@ struct mon_cli_iface monitor_be_methods = {
     .clearEnumCache = NULL,
 };
 
-struct sbus_interface monitor_be_interface = {
-    MONITOR_PATH,
-    &monitor_be_methods.vtable,
-    NULL
-};
-
-static int client_registration(struct sbus_request *dbus_req);
-static int be_get_account_info(struct sbus_request *dbus_req);
-static int be_pam_handler(struct sbus_request *dbus_req);
-static int be_sudo_handler(struct sbus_request *dbus_req);
-static int be_autofs_handler(struct sbus_request *dbus_req);
-static int be_host_handler(struct sbus_request *dbus_req);
-static int be_get_subdomains(struct sbus_request *dbus_req);
+static int client_registration(struct sbus_request *dbus_req, void *data);
+static int be_get_account_info(struct sbus_request *dbus_req, void *user_data);
+static int be_pam_handler(struct sbus_request *dbus_req, void *user_data);
+static int be_sudo_handler(struct sbus_request *dbus_req, void *user_data);
+static int be_autofs_handler(struct sbus_request *dbus_req, void *user_data);
+static int be_host_handler(struct sbus_request *dbus_req, void *user_data);
+static int be_get_subdomains(struct sbus_request *dbus_req, void *user_data);
 
 struct data_provider_iface be_methods = {
     { &data_provider_iface_meta, 0 },
@@ -96,12 +90,6 @@ struct data_provider_iface be_methods = {
     .getAccountInfo = be_get_account_info,
 };
 
-struct sbus_interface be_interface = {
-    DP_PATH,
-    &be_methods.vtable,
-    NULL
-};
-
 static struct bet_data bet_data[] = {
     {BET_NULL, NULL, NULL},
     {BET_ID, CONFDB_DOMAIN_ID_PROVIDER, "sssm_%s_id_init"},
@@ -565,13 +553,12 @@ static void get_subdomains_callback(struct be_req *req,
     talloc_free(req);
 }
 
-static int be_get_subdomains(struct sbus_request *dbus_req)
+static int be_get_subdomains(struct sbus_request *dbus_req, void *user_data)
 {
     struct be_subdom_req *req;
     struct be_req *be_req = NULL;
     struct be_client *becli;
     DBusError dbus_error;
-    void *user_data;
     dbus_bool_t force;
     char *domain_hint;
     dbus_uint16_t err_maj;
@@ -579,8 +566,6 @@ static int be_get_subdomains(struct sbus_request *dbus_req)
     const char *err_msg;
     int ret;
 
-    user_data = sbus_conn_get_private_data(dbus_req->conn);
-    if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
@@ -1046,13 +1031,12 @@ errno_t be_get_account_info_recv(struct tevent_req *req,
     return EOK;
 }
 
-static int be_get_account_info(struct sbus_request *dbus_req)
+static int be_get_account_info(struct sbus_request *dbus_req, void *user_data)
 {
     struct be_acct_req *req;
     struct be_req *be_req;
     struct be_client *becli;
     DBusError dbus_error;
-    void *user_data;
     uint32_t type;
     char *filter;
     char *domain;
@@ -1064,8 +1048,6 @@ static int be_get_account_info(struct sbus_request *dbus_req)
 
     be_req = NULL;
 
-    user_data = sbus_conn_get_private_data(dbus_req->conn);
-    if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
@@ -1303,19 +1285,16 @@ done:
     talloc_free(req);
 }
 
-static int be_pam_handler(struct sbus_request *dbus_req)
+static int be_pam_handler(struct sbus_request *dbus_req, void *user_data)
 {
     DBusError dbus_error;
     DBusMessage *reply;
     struct be_client *becli;
     dbus_bool_t ret;
-    void *user_data;
     struct pam_data *pd = NULL;
     struct be_req *be_req = NULL;
     enum bet_type target = BET_NULL;
 
-    user_data = sbus_conn_get_private_data(dbus_req->conn);
-    if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
@@ -1465,7 +1444,7 @@ static void be_sudo_handler_callback(struct be_req *req,
     talloc_free(req);
 }
 
-static int be_sudo_handler(struct sbus_request *dbus_req)
+static int be_sudo_handler(struct sbus_request *dbus_req, void *user_data)
 {
     DBusError dbus_error;
     DBusMessageIter iter;
@@ -1473,7 +1452,6 @@ static int be_sudo_handler(struct sbus_request *dbus_req)
     struct be_client *be_cli = NULL;
     struct be_req *be_req = NULL;
     struct be_sudo_req *sudo_req = NULL;
-    void *user_data = NULL;
     int ret = 0;
     uint32_t type;
     uint32_t rules_num = 0;
@@ -1483,11 +1461,6 @@ static int be_sudo_handler(struct sbus_request *dbus_req)
 
     DEBUG(SSSDBG_TRACE_FUNC, "Entering be_sudo_handler()\n");
 
-    user_data = sbus_conn_get_private_data(dbus_req->conn);
-    if (user_data == NULL) {
-        return EINVAL;
-    }
-
     be_cli = talloc_get_type(user_data, struct be_client);
     if (be_cli == NULL) {
         return EINVAL;
@@ -1632,13 +1605,12 @@ static void be_autofs_handler_callback(struct be_req *req,
                                        int errnum,
                                        const char *errstr);
 
-static int be_autofs_handler(struct sbus_request *dbus_req)
+static int be_autofs_handler(struct sbus_request *dbus_req, void *user_data)
 {
     DBusError dbus_error;
     struct be_client *be_cli = NULL;
     struct be_req *be_req = NULL;
     struct be_autofs_req *be_autofs_req = NULL;
-    void *user_data = NULL;
     int ret = 0;
     uint32_t type;
     char *filter;
@@ -1649,12 +1621,6 @@ static int be_autofs_handler(struct sbus_request *dbus_req)
 
     DEBUG(SSSDBG_TRACE_FUNC, "Entering be_autofs_handler()\n");
 
-    user_data = sbus_conn_get_private_data(dbus_req->conn);
-    if (user_data == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get SBUS private data\n");
-        return EINVAL;
-    }
-
     be_cli = talloc_get_type(user_data, struct be_client);
     if (be_cli == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get back end client context\n");
@@ -1847,13 +1813,12 @@ static void be_autofs_handler_callback(struct be_req *req,
     talloc_free(req);
 }
 
-static int be_host_handler(struct sbus_request *dbus_req)
+static int be_host_handler(struct sbus_request *dbus_req, void *user_data)
 {
     struct be_host_req *req;
     struct be_req *be_req;
     struct be_client *becli;
     DBusError dbus_error;
-    void *user_data;
     uint32_t flags;
     char *filter;
     int ret;
@@ -1863,8 +1828,6 @@ static int be_host_handler(struct sbus_request *dbus_req)
 
     be_req = NULL;
 
-    user_data = sbus_conn_get_private_data(dbus_req->conn);
-    if (!user_data) return EINVAL;
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
@@ -2030,7 +1993,7 @@ static int be_client_destructor(void *ctx)
     return 0;
 }
 
-static int client_registration(struct sbus_request *dbus_req)
+static int client_registration(struct sbus_request *dbus_req, void *data)
 {
     dbus_uint16_t version = DATA_PROVIDER_VERSION;
     struct sbus_connection *conn;
@@ -2039,11 +2002,9 @@ static int client_registration(struct sbus_request *dbus_req)
     dbus_uint16_t cli_ver;
     char *cli_name;
     dbus_bool_t dbret;
-    void *data;
     int ret;
 
     conn = dbus_req->conn;
-    data = sbus_conn_get_private_data(conn);
     becli = talloc_get_type(data, struct be_client);
     if (!becli) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
@@ -2230,6 +2191,7 @@ static void init_timeout(struct tevent_context *ev,
 
 static int be_client_init(struct sbus_connection *conn, void *data)
 {
+    struct sbus_interface *intf;
     struct be_ctx *bectx;
     struct be_client *becli;
     struct timeval tv;
@@ -2264,9 +2226,12 @@ static int be_client_init(struct sbus_connection *conn, void *data)
 
     /* Attach the client context to the connection context, so that it is
      * always available when we need to manage the connection. */
-    sbus_conn_set_private_data(conn, becli);
+    intf = sbus_new_interface(conn, DP_PATH, &be_methods.vtable, becli);
+    if (!intf) {
+        return ENOMEM;
+    }
 
-    return EOK;
+    return sbus_conn_add_interface(conn, intf);
 }
 
 /* be_srv_init
@@ -2284,8 +2249,7 @@ static int be_srv_init(struct be_ctx *ctx)
     }
 
     ret = sbus_new_server(ctx, ctx->ev, sbus_address,
-                          &be_interface, true, &ctx->sbus_srv,
-                          be_client_init, ctx);
+                          true, &ctx->sbus_srv, be_client_init, ctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
         return ret;
@@ -2599,7 +2563,7 @@ int be_process_init(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = sss_monitor_init(ctx, ctx->ev, &monitor_be_interface,
+    ret = sss_monitor_init(ctx, ctx->ev, &monitor_be_methods,
                            ctx->identity, DATA_PROVIDER_VERSION,
                            ctx, &ctx->mon_conn);
     if (ret != EOK) {
@@ -2879,38 +2843,37 @@ int main(int argc, const char *argv[])
 }
 #endif
 
-static int data_provider_res_init(struct sbus_request *dbus_req)
+static int data_provider_res_init(struct sbus_request *dbus_req, void *data)
 {
     struct be_ctx *be_ctx;
-    be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn), struct be_ctx);
+    be_ctx = talloc_get_type(data, struct be_ctx);
 
     resolv_reread_configuration(be_ctx->be_res->resolv);
     check_if_online(be_ctx);
 
-    return monitor_common_res_init(dbus_req);
+    return monitor_common_res_init(dbus_req, data);
 }
 
-static int data_provider_go_offline(struct sbus_request *dbus_req)
+static int data_provider_go_offline(struct sbus_request *dbus_req, void *data)
 {
     struct be_ctx *be_ctx;
-    be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn), struct be_ctx);
+    be_ctx = talloc_get_type(data, struct be_ctx);
     be_mark_offline(be_ctx);
     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-static int data_provider_reset_offline(struct sbus_request *dbus_req)
+static int data_provider_reset_offline(struct sbus_request *dbus_req, void *data)
 {
     struct be_ctx *be_ctx;
-    be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn), struct be_ctx);
+    be_ctx = talloc_get_type(data, struct be_ctx);
     check_if_online(be_ctx);
     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-static int data_provider_logrotate(struct sbus_request *dbus_req)
+static int data_provider_logrotate(struct sbus_request *dbus_req, void *data)
 {
     errno_t ret;
-    struct be_ctx *be_ctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
-                                            struct be_ctx);
+    struct be_ctx *be_ctx = talloc_get_type(data, struct be_ctx);
 
     ret = monitor_common_rotate_logs(be_ctx->cdb, be_ctx->conf_path);
     if (ret != EOK) return ret;
diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c
index 44d4fd6623e2ab4dc8dc6c7c7caf5d3029ec25b5..8889be3b47f773e845e616b456bf6f9873f39d0e 100644
--- a/src/providers/proxy/proxy_child.c
+++ b/src/providers/proxy/proxy_child.c
@@ -47,7 +47,7 @@
 
 #include "providers/dp_backend.h"
 
-static int pc_pam_handler(struct sbus_request *dbus_req);
+static int pc_pam_handler(struct sbus_request *dbus_req, void *user_data);
 
 struct data_provider_iface pc_methods = {
     { &data_provider_iface_meta, 0 },
@@ -60,12 +60,6 @@ struct data_provider_iface pc_methods = {
     .getAccountInfo = NULL,
 };
 
-struct sbus_interface pc_interface = {
-    DP_PATH,
-    &pc_methods.vtable,
-    NULL
-};
-
 struct pc_ctx {
     struct tevent_context *ev;
     struct confdb_ctx *cdb;
@@ -310,20 +304,14 @@ fail:
     return ret;
 }
 
-static int pc_pam_handler(struct sbus_request *dbus_req)
+static int pc_pam_handler(struct sbus_request *dbus_req, void *user_data)
 {
     DBusError dbus_error;
     DBusMessage *reply;
     struct pc_ctx *pc_ctx;
     errno_t ret;
-    void *user_data;
     struct pam_data *pd = NULL;
 
-    user_data = sbus_conn_get_private_data(dbus_req->conn);
-    if (!user_data) {
-        ret = EINVAL;
-        goto done;
-    }
     pc_ctx = talloc_get_type(user_data, struct pc_ctx);
     if (!pc_ctx) {
         ret = EINVAL;
@@ -393,6 +381,7 @@ int proxy_child_send_id(struct sbus_connection *conn,
                         uint32_t id);
 static int proxy_cli_init(struct pc_ctx *ctx)
 {
+    struct sbus_interface *intf;
     char *sbus_address;
     int ret;
 
@@ -404,14 +393,23 @@ static int proxy_cli_init(struct pc_ctx *ctx)
         return ENOMEM;
     }
 
-    ret = sbus_client_init(ctx, ctx->ev, sbus_address,
-                           &pc_interface, &ctx->conn,
-                           NULL, ctx);
+    ret = sbus_client_init(ctx, ctx->ev, sbus_address, &ctx->conn);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "sbus_client_init failed.\n");
         return ret;
     }
 
+    intf = sbus_new_interface(ctx, DP_PATH, &pc_methods.vtable, ctx);
+    if (!intf) {
+        ret = ENOMEM;
+    } else {
+        ret = sbus_conn_add_interface(ctx->conn, intf);
+    }
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export proxy.\n");
+        return ret;
+    }
+
     ret = proxy_child_send_id(ctx->conn, DATA_PROVIDER_VERSION, ctx->id);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "dp_common_send_id failed.\n");
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
index 70fe337cde7925311295f0b682860aa3d5de0a94..0206ec15b670e1763102ee2d99e18918a56c56e7 100644
--- a/src/providers/proxy/proxy_init.c
+++ b/src/providers/proxy/proxy_init.c
@@ -27,7 +27,7 @@
 #include "util/sss_format.h"
 #include "providers/proxy/proxy.h"
 
-static int client_registration(struct sbus_request *dbus_req);
+static int client_registration(struct sbus_request *dbus_req, void *data);
 
 static struct data_provider_iface proxy_methods = {
     { &data_provider_iface_meta, 0 },
@@ -40,12 +40,6 @@ static struct data_provider_iface proxy_methods = {
     .getAccountInfo = NULL,
 };
 
-struct sbus_interface proxy_interface = {
-    DP_PATH,
-    &proxy_methods.vtable,
-    NULL
-};
-
 static void proxy_shutdown(struct be_req *req)
 {
     /* TODO: Clean up any internal data */
@@ -337,6 +331,7 @@ static int proxy_client_init(struct sbus_connection *conn, void *data)
 {
     struct proxy_auth_ctx *proxy_auth_ctx;
     struct proxy_client *proxy_cli;
+    struct sbus_interface *intf;
     struct timeval tv;
 
     proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);
@@ -369,9 +364,12 @@ static int proxy_client_init(struct sbus_connection *conn, void *data)
 
     /* Attach the client context to the connection context, so that it is
      * always available when we need to manage the connection. */
-    sbus_conn_set_private_data(conn, proxy_cli);
+    intf = sbus_new_interface(conn, DP_PATH, &proxy_methods.vtable, proxy_cli);
+    if (!intf) {
+        return ENOMEM;
+    }
 
-    return EOK;
+    return sbus_conn_add_interface(conn, intf);
 }
 
 static void init_timeout(struct tevent_context *ev,
@@ -394,7 +392,7 @@ static void init_timeout(struct tevent_context *ev,
      */
 }
 
-static int client_registration(struct sbus_request *dbus_req)
+static int client_registration(struct sbus_request *dbus_req, void *data)
 {
     dbus_uint16_t version = DATA_PROVIDER_VERSION;
     struct sbus_connection *conn;
@@ -403,7 +401,6 @@ static int client_registration(struct sbus_request *dbus_req)
     dbus_uint16_t cli_ver;
     uint32_t cli_id;
     dbus_bool_t dbret;
-    void *data;
     int hret;
     hash_key_t key;
     hash_value_t value;
@@ -413,7 +410,6 @@ static int client_registration(struct sbus_request *dbus_req)
     int ret;
 
     conn = dbus_req->conn;
-    data = sbus_conn_get_private_data(conn);
     proxy_cli = talloc_get_type(data, struct proxy_client);
     if (!proxy_cli) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
@@ -535,7 +531,7 @@ int sssm_proxy_auth_init(struct be_ctx *bectx,
         goto done;
     }
 
-    ret = sbus_new_server(ctx, bectx->ev, sbus_address, &proxy_interface,
+    ret = sbus_new_server(ctx, bectx->ev, sbus_address,
                           false, &ctx->sbus_srv, proxy_client_init, ctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
index b447a063448e420dac0b0ad6e9210a26b96d9c79..9b5aa02dd53772a569da71a79e600dfa2ba5f1ef 100644
--- a/src/responder/autofs/autofssrv.c
+++ b/src/responder/autofs/autofssrv.c
@@ -29,7 +29,7 @@
 #include "providers/data_provider.h"
 #include "responder/autofs/autofs_private.h"
 
-static int autofs_clean_hash_table(struct sbus_request *dbus_req);
+static int autofs_clean_hash_table(struct sbus_request *dbus_req, void *data);
 
 struct mon_cli_iface monitor_autofs_methods = {
     { &mon_cli_iface_meta, 0 },
@@ -43,12 +43,6 @@ struct mon_cli_iface monitor_autofs_methods = {
     .clearEnumCache = autofs_clean_hash_table,
 };
 
-struct sbus_interface monitor_autofs_interface = {
-    MONITOR_PATH,
-    &monitor_autofs_methods.vtable,
-    NULL
-};
-
 static struct data_provider_iface autofs_dp_methods = {
     { &data_provider_iface_meta, 0 },
     .RegisterService = NULL,
@@ -60,12 +54,6 @@ static struct data_provider_iface autofs_dp_methods = {
     .getAccountInfo = NULL,
 };
 
-struct sbus_interface autofs_dp_interface = {
-    DP_PATH,
-    &autofs_dp_methods.vtable,
-    NULL
-};
-
 static errno_t
 autofs_get_config(struct autofs_ctx *actx,
                   struct confdb_ctx *cdb)
@@ -111,10 +99,9 @@ autofs_dp_reconnect_init(struct sbus_connection *conn,
                                  be_conn->domain->name);
 }
 
-static int autofs_clean_hash_table(struct sbus_request *dbus_req)
+static int autofs_clean_hash_table(struct sbus_request *dbus_req, void *data)
 {
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
-                                            struct resp_ctx);
+    struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
     struct autofs_ctx *actx =
             talloc_get_type(rctx->pvt_ctx, struct autofs_ctx);
     errno_t ret;
@@ -148,9 +135,9 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
                            CONFDB_AUTOFS_CONF_ENTRY,
                            SSS_AUTOFS_SBUS_SERVICE_NAME,
                            SSS_AUTOFS_SBUS_SERVICE_VERSION,
-                           &monitor_autofs_interface,
+                           &monitor_autofs_methods,
                            "autofs",
-                           &autofs_dp_interface,
+                           &autofs_dp_methods.vtable,
                            &rctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 9d7cf3b54cefe339dcafce9a54b5e085d37212ae..98e363c3efcc29de3224336c2dbc069861f09b3d 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -68,7 +68,6 @@ struct be_conn {
     struct sss_domain_info *domain;
 
     char *sbus_address;
-    struct sbus_interface *intf;
     struct sbus_connection *conn;
 };
 
@@ -142,7 +141,16 @@ struct sss_cmd_table {
     int (*fn)(struct cli_ctx *cctx);
 };
 
-/* responder_common.c */
+/* from generated code */
+struct mon_cli_iface;
+
+/*
+ * responder_common.c
+ *
+ * NOTE: We would like to use more strong typing for the @dp_vtable argument
+ * but can't since it accepts either a struct data_provider_iface
+ * or struct data_provider_rev_iface. So pass the base struct: sbus_vtable
+ */
 int sss_process_init(TALLOC_CTX *mem_ctx,
                      struct tevent_context *ev,
                      struct confdb_ctx *cdb,
@@ -152,9 +160,9 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
                      const char *confdb_service_path,
                      const char *svc_name,
                      uint16_t svc_version,
-                     struct sbus_interface *monitor_intf,
+                     struct mon_cli_iface *monitor_intf,
                      const char *cli_name,
-                     struct sbus_interface *dp_intf,
+                     struct sbus_vtable *dp_intf,
                      struct resp_ctx **responder_ctx);
 
 int sss_parse_name(TALLOC_CTX *memctx,
@@ -214,7 +222,7 @@ struct dp_callback_ctx {
 
 void handle_requests_after_reconnect(struct resp_ctx *rctx);
 
-int responder_logrotate(struct sbus_request *dbus_req);
+int responder_logrotate(struct sbus_request *dbus_req, void *data);
 
 /* Each responder-specific request must create a constructor
  * function that creates a DBus Message that would be sent to
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index dabf5c053904d0e3df84b849bd0033bc78c1392e..2dd62ffcdc7961a391104bd49c3c8afcb6f1b361 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -534,10 +534,11 @@ static void idle_handler(struct tevent_context *ev,
 }
 
 static int sss_dp_init(struct resp_ctx *rctx,
-                       struct sbus_interface *intf,
+                       struct sbus_vtable *dp_intf,
                        const char *cli_name,
                        struct sss_domain_info *domain)
 {
+    struct sbus_interface *intf;
     struct be_conn *be_conn;
     int ret;
 
@@ -546,7 +547,6 @@ static int sss_dp_init(struct resp_ctx *rctx,
 
     be_conn->cli_name = cli_name;
     be_conn->domain = domain;
-    be_conn->intf = intf;
     be_conn->rctx = rctx;
 
     /* Set up SBUS connection to the monitor */
@@ -557,13 +557,23 @@ static int sss_dp_init(struct resp_ctx *rctx,
     }
     ret = sbus_client_init(rctx, rctx->ev,
                            be_conn->sbus_address,
-                           intf, &be_conn->conn,
-                           NULL, rctx);
+                           &be_conn->conn);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to connect to monitor services.\n");
         return ret;
     }
 
+    intf = sbus_new_interface(rctx, DP_PATH, dp_intf, rctx);
+    if (!intf) {
+        ret = ENOMEM;
+    } else {
+        ret = sbus_conn_add_interface(be_conn->conn, intf);
+    }
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export data provider.\n");
+        return ret;
+    }
+
     DLIST_ADD_END(rctx->be_conns, be_conn, struct be_conn *);
 
     /* Identify ourselves to the DP */
@@ -762,9 +772,9 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
                      const char *confdb_service_path,
                      const char *svc_name,
                      uint16_t svc_version,
-                     struct sbus_interface *monitor_intf,
+                     struct mon_cli_iface *monitor_intf,
                      const char *cli_name,
-                     struct sbus_interface *dp_intf,
+                     struct sbus_vtable *dp_intf,
                      struct resp_ctx **responder_ctx)
 {
     struct resp_ctx *rctx;
@@ -989,11 +999,10 @@ done:
     return ret;
 }
 
-int responder_logrotate(struct sbus_request *dbus_req)
+int responder_logrotate(struct sbus_request *dbus_req, void *data)
 {
     errno_t ret;
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
-                                            struct resp_ctx);
+    struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
 
     ret = monitor_common_rotate_logs(rctx->cdb, rctx->confdb_service_path);
     if (ret != EOK) return ret;
diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
index db4e18762c05ed5c36fbe18da3c6e5a80d8083ce..5e62377229de49034c5d80e87495a5d6dedf3229 100644
--- a/src/responder/nss/nsssrv.c
+++ b/src/responder/nss/nsssrv.c
@@ -55,8 +55,8 @@
 #define SHELL_REALLOC_INCREMENT 5
 #define SHELL_REALLOC_MAX       50
 
-static int nss_clear_memcache(struct sbus_request *dbus_req);
-static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req);
+static int nss_clear_memcache(struct sbus_request *dbus_req, void *data);
+static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req, void *data);
 
 struct mon_cli_iface monitor_nss_methods = {
     { &mon_cli_iface_meta, 0 },
@@ -70,18 +70,11 @@ struct mon_cli_iface monitor_nss_methods = {
     .clearEnumCache = nss_clear_netgroup_hash_table
 };
 
-struct sbus_interface monitor_nss_interface = {
-    MONITOR_PATH,
-    &monitor_nss_methods.vtable,
-    NULL,
-};
-
-static int nss_clear_memcache(struct sbus_request *dbus_req)
+static int nss_clear_memcache(struct sbus_request *dbus_req, void *data)
 {
     errno_t ret;
     int memcache_timeout;
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
-                                            struct resp_ctx);
+    struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
     struct nss_ctx *nctx = (struct nss_ctx*) rctx->pvt_ctx;
 
     ret = unlink(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG);
@@ -134,11 +127,10 @@ done:
     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
 }
 
-static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req)
+static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req, void *data)
 {
     errno_t ret;
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
-                                            struct resp_ctx);
+    struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
     struct nss_ctx *nctx = (struct nss_ctx*) rctx->pvt_ctx;
 
     ret = nss_orphan_netgroups(nctx);
@@ -304,10 +296,9 @@ done:
     return ret;
 }
 
-static int nss_update_memcache(struct sbus_request *dbus_req)
+static int nss_update_memcache(struct sbus_request *dbus_req, void *data)
 {
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
-                                            struct resp_ctx);
+    struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
     struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
 
     nss_update_pw_memcache(nctx);
@@ -316,10 +307,9 @@ static int nss_update_memcache(struct sbus_request *dbus_req)
     return EOK;
 }
 
-static int nss_memcache_initgr_check(struct sbus_request *dbus_req)
+static int nss_memcache_initgr_check(struct sbus_request *dbus_req, void *data)
 {
-    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(dbus_req->conn),
-                                            struct resp_ctx);
+    struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
     struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
     DBusError dbus_error;
     dbus_bool_t dbret;
@@ -359,13 +349,6 @@ static struct data_provider_rev_iface nss_dp_methods = {
     .initgrCheck = nss_memcache_initgr_check
 };
 
-struct sbus_interface nss_dp_interface = {
-    DP_PATH,
-    &nss_dp_methods.vtable,
-    NULL
-};
-
-
 static void nss_dp_reconnect_init(struct sbus_connection *conn,
                                   int status, void *pvt)
 {
@@ -417,8 +400,8 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
                            CONFDB_NSS_CONF_ENTRY,
                            NSS_SBUS_SERVICE_NAME,
                            NSS_SBUS_SERVICE_VERSION,
-                           &monitor_nss_interface,
-                           "NSS", &nss_dp_interface,
+                           &monitor_nss_methods,
+                           "NSS", &nss_dp_methods.vtable,
                            &rctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
index 81eb303ae5b0a311575be64e0e64747d9101d11a..ed51cb86974308213c330c0a7a85699ad8b157ee 100644
--- a/src/responder/pac/pacsrv.c
+++ b/src/responder/pac/pacsrv.c
@@ -60,12 +60,6 @@ struct mon_cli_iface monitor_pac_methods = {
     .clearEnumCache = NULL,
 };
 
-struct sbus_interface monitor_pac_interface = {
-    MONITOR_PATH,
-    &monitor_pac_methods.vtable,
-    NULL
-};
-
 static struct data_provider_iface pac_dp_methods = {
     { &data_provider_iface_meta, 0 },
     .RegisterService = NULL,
@@ -77,13 +71,6 @@ static struct data_provider_iface pac_dp_methods = {
     .getAccountInfo = NULL,
 };
 
-struct sbus_interface pac_dp_interface = {
-    DP_PATH,
-    &pac_dp_methods.vtable,
-    NULL
-};
-
-
 /* TODO: check if this can be made generic for all responders */
 static void pac_dp_reconnect_init(struct sbus_connection *conn,
                                   int status, void *pvt)
@@ -135,8 +122,8 @@ int pac_process_init(TALLOC_CTX *mem_ctx,
                            CONFDB_PAC_CONF_ENTRY,
                            PAC_SBUS_SERVICE_NAME,
                            PAC_SBUS_SERVICE_VERSION,
-                           &monitor_pac_interface,
-                           "PAC", &pac_dp_interface,
+                           &monitor_pac_methods,
+                           "PAC", &pac_dp_methods.vtable,
                            &rctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
index af1d1493dadcae6f72924a9921ae5c45eb1998d4..0fbb8d3f38c34900d6c6bebaeebee4c4688f45e2 100644
--- a/src/responder/pam/pamsrv.c
+++ b/src/responder/pam/pamsrv.c
@@ -59,12 +59,6 @@ struct mon_cli_iface monitor_pam_methods = {
     .clearEnumCache = NULL,
 };
 
-struct sbus_interface monitor_pam_interface = {
-    MONITOR_PATH,
-    &monitor_pam_methods.vtable,
-    NULL
-};
-
 static struct data_provider_iface pam_dp_methods = {
     { &data_provider_iface_meta, 0 },
     .RegisterService = NULL,
@@ -76,13 +70,6 @@ static struct data_provider_iface pam_dp_methods = {
     .getAccountInfo = NULL,
 };
 
-struct sbus_interface pam_dp_interface = {
-    DP_PATH,
-    &pam_dp_methods.vtable,
-    NULL
-};
-
-
 static void pam_dp_reconnect_init(struct sbus_connection *conn, int status, void *pvt)
 {
     struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn);
@@ -131,8 +118,8 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
                            CONFDB_PAM_CONF_ENTRY,
                            SSS_PAM_SBUS_SERVICE_NAME,
                            SSS_PAM_SBUS_SERVICE_VERSION,
-                           &monitor_pam_interface,
-                           "PAM", &pam_dp_interface,
+                           &monitor_pam_methods,
+                           "PAM", &pam_dp_methods.vtable,
                            &rctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
index fb0738f6c8cfb62064659be210d59bfee54827cb..30142ae0d8f57f86c76dd85f25020b599d90bbdf 100644
--- a/src/responder/ssh/sshsrv.c
+++ b/src/responder/ssh/sshsrv.c
@@ -40,12 +40,6 @@ struct mon_cli_iface monitor_ssh_methods = {
     .clearEnumCache = NULL,
 };
 
-struct sbus_interface monitor_ssh_interface = {
-    MONITOR_PATH,
-    &monitor_ssh_methods.vtable,
-    NULL
-};
-
 static struct data_provider_iface ssh_dp_methods = {
     { &data_provider_iface_meta, 0 },
     .RegisterService = NULL,
@@ -57,12 +51,6 @@ static struct data_provider_iface ssh_dp_methods = {
     .getAccountInfo = NULL,
 };
 
-struct sbus_interface ssh_dp_interface = {
-    DP_PATH,
-    &ssh_dp_methods.vtable,
-    NULL
-};
-
 static void ssh_dp_reconnect_init(struct sbus_connection *conn,
                                   int status, void *pvt)
 {
@@ -107,9 +95,9 @@ int ssh_process_init(TALLOC_CTX *mem_ctx,
                            CONFDB_SSH_CONF_ENTRY,
                            SSS_SSH_SBUS_SERVICE_NAME,
                            SSS_SSH_SBUS_SERVICE_VERSION,
-                           &monitor_ssh_interface,
+                           &monitor_ssh_methods,
                            "SSH",
-                           &ssh_dp_interface,
+                           &ssh_dp_methods.vtable,
                            &rctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
index 1ad260b3578373664da6aec135a9a3aaa62d4931..a70d944a9e06a3236c85aff56c06c39b6888dac0 100644
--- a/src/responder/sudo/sudosrv.c
+++ b/src/responder/sudo/sudosrv.c
@@ -40,12 +40,6 @@ struct mon_cli_iface monitor_sudo_methods = {
     .clearEnumCache = NULL,
 };
 
-struct sbus_interface monitor_sudo_interface = {
-    MONITOR_PATH,
-    &monitor_sudo_methods.vtable,
-    NULL
-};
-
 static struct data_provider_iface sudo_dp_methods = {
     { &data_provider_iface_meta, 0 },
     .RegisterService = NULL,
@@ -57,12 +51,6 @@ static struct data_provider_iface sudo_dp_methods = {
     .getAccountInfo = NULL,
 };
 
-struct sbus_interface sudo_dp_interface = {
-    DP_PATH,
-    &sudo_dp_methods.vtable,
-    NULL
-};
-
 static void sudo_dp_reconnect_init(struct sbus_connection *conn,
                                    int status,
                                    void *pvt)
@@ -108,9 +96,9 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
                            CONFDB_SUDO_CONF_ENTRY,
                            SSS_SUDO_SBUS_SERVICE_NAME,
                            SSS_SUDO_SBUS_SERVICE_VERSION,
-                           &monitor_sudo_interface,
+                           &monitor_sudo_methods,
                            "SUDO",
-                           &sudo_dp_interface,
+                           &sudo_dp_methods.vtable,
                            &rctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "sss_process_init() failed\n");
diff --git a/src/sbus/sbus_client.c b/src/sbus/sbus_client.c
index f516555a75cec70ff2cc9bd6ff11949df5aa03b7..ce862534db63af4819a41a176b852640bc38b811 100644
--- a/src/sbus/sbus_client.c
+++ b/src/sbus/sbus_client.c
@@ -26,10 +26,7 @@
 int sbus_client_init(TALLOC_CTX *mem_ctx,
                      struct tevent_context *ev,
                      const char *server_address,
-                     struct sbus_interface *intf,
-                     struct sbus_connection **_conn,
-                     sbus_conn_destructor_fn destructor,
-                     void *conn_pvt_data)
+                     struct sbus_connection **_conn)
 {
     struct sbus_connection *conn = NULL;
     int ret;
@@ -53,15 +50,11 @@ int sbus_client_init(TALLOC_CTX *mem_ctx,
         return EIO;
     }
 
-    ret = sbus_new_connection(mem_ctx, ev, server_address, intf, &conn);
+    ret = sbus_new_connection(mem_ctx, ev, server_address, &conn);
     if (ret != EOK) {
         goto fail;
     }
 
-    /* Set connection destructor and private data */
-    sbus_conn_set_destructor(conn, destructor);
-    sbus_conn_set_private_data(conn, conn_pvt_data);
-
     *_conn = conn;
     return EOK;
 
diff --git a/src/sbus/sbus_client.h b/src/sbus/sbus_client.h
index 742f8a10c3516232dec77808ef2daf9bc191745c..aea1342ea89257d019703f396caa2fc2801b02e2 100644
--- a/src/sbus/sbus_client.h
+++ b/src/sbus/sbus_client.h
@@ -28,9 +28,6 @@
 int sbus_client_init(TALLOC_CTX *mem_ctx,
                      struct tevent_context *ev,
                      const char *server_address,
-                     struct sbus_interface *intf,
-                     struct sbus_connection **_conn,
-                     sbus_conn_destructor_fn destructor,
-                     void *conn_pvt_data);
+                     struct sbus_connection **_conn);
 
 #endif /* SBUS_CLIENT_H_ */
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index dcb66907916606baede8a9744d775d7cce8a6e68..ef728bd30e6b52cb18bd5d68f0d4f4e759358eca 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -23,12 +23,13 @@
 #define _SSSD_DBUS_H_
 
 struct sbus_connection;
-
+struct sbus_interface;
 struct sbus_request;
 
 #include <dbus/dbus.h>
 
-typedef int (*sbus_msg_handler_fn)(struct sbus_request *dbus_req);
+typedef int (*sbus_msg_handler_fn)(struct sbus_request *dbus_req,
+                                   void *instance_data);
 
 /*
  * sbus_conn_destructor_fn
@@ -79,14 +80,28 @@ struct sbus_vtable {
 struct sbus_interface {
     const char *path;
     struct sbus_vtable *vtable;
-    sbus_msg_handler_fn introspect_fn;
+    void *instance_data;
 };
 
+/*
+ * Creates a new struct sbus_interface instance to be exported by a DBus
+ * service.
+ *
+ * Pass the result to sbus_conn_add_interface(). The interface
+ * will be exported at @object_path. The method handlers are represented by
+ * @iface_vtable. @instance_data contains additional caller specific data
+ * which is made available to handlers.
+ */
+struct sbus_interface *
+sbus_new_interface(TALLOC_CTX *mem_ctx,
+                   const char *object_path,
+                   struct sbus_vtable *iface_vtable,
+                   void *instance_data);
+
 /* Server Functions */
 int sbus_new_server(TALLOC_CTX *mem_ctx,
                     struct tevent_context *ev,
                     const char *address,
-                    struct sbus_interface *intf,
                     bool use_symlink,
                     struct sbus_connection **server,
                     sbus_server_conn_init_fn init_fn, void *init_pvt_data);
@@ -103,7 +118,6 @@ int sbus_new_server(TALLOC_CTX *mem_ctx,
 int sbus_new_connection(TALLOC_CTX *ctx,
                         struct tevent_context *ev,
                         const char *address,
-                        struct sbus_interface *intf,
                         struct sbus_connection **conn);
 
 /* sbus_add_connection
@@ -121,19 +135,11 @@ int sbus_new_connection(TALLOC_CTX *ctx,
 int sbus_init_connection(TALLOC_CTX *ctx,
                          struct tevent_context *ev,
                          DBusConnection *dbus_conn,
-                         struct sbus_interface *intf,
                          int connection_type,
                          struct sbus_connection **_conn);
 
-void sbus_conn_set_destructor(struct sbus_connection *conn,
-                              sbus_conn_destructor_fn destructor);
-
-int sbus_default_connection_destructor(void *ctx);
-
 DBusConnection *sbus_get_connection(struct sbus_connection *conn);
 void sbus_disconnect(struct sbus_connection *conn);
-void sbus_conn_set_private_data(struct sbus_connection *conn, void *pvt_data);
-void *sbus_conn_get_private_data(struct sbus_connection *conn);
 int sbus_conn_add_interface(struct sbus_connection *conn,
                             struct sbus_interface *intf);
 bool sbus_conn_disconnecting(struct sbus_connection *conn);
diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
index 6535bc90e66e81d5c30ccd9fc598ca9b64a498be..1d927c8477ea4bd46cb5f5ed1d323d6a17fc9502 100644
--- a/src/sbus/sssd_dbus_connection.c
+++ b/src/sbus/sssd_dbus_connection.c
@@ -159,7 +159,6 @@ static int sbus_conn_set_fns(struct sbus_connection *conn);
 int sbus_init_connection(TALLOC_CTX *ctx,
                          struct tevent_context *ev,
                          DBusConnection *dbus_conn,
-                         struct sbus_interface *intf,
                          int connection_type,
                          struct sbus_connection **_conn)
 {
@@ -174,12 +173,6 @@ int sbus_init_connection(TALLOC_CTX *ctx,
     conn->dbus.conn = dbus_conn;
     conn->connection_type = connection_type;
 
-    ret = sbus_conn_add_interface(conn, intf);
-    if (ret != EOK) {
-        talloc_free(conn);
-        return ret;
-    }
-
     ret = sbus_conn_set_fns(conn);
     if (ret != EOK) {
         talloc_free(conn);
@@ -194,13 +187,6 @@ static int sbus_conn_set_fns(struct sbus_connection *conn)
 {
     dbus_bool_t dbret;
 
-    /*
-     * Set the default destructor
-     * Connections can override this with
-     * sbus_conn_set_destructor
-     */
-    sbus_conn_set_destructor(conn, NULL);
-
     /* Set up DBusWatch functions */
     dbret = dbus_connection_set_watch_functions(conn->dbus.conn,
                                                 sbus_add_watch,
@@ -244,8 +230,7 @@ static int sbus_conn_set_fns(struct sbus_connection *conn)
 }
 
 int sbus_new_connection(TALLOC_CTX *ctx, struct tevent_context *ev,
-                        const char *address, struct sbus_interface *intf,
-                        struct sbus_connection **_conn)
+                        const char *address, struct sbus_connection **_conn)
 {
     struct sbus_connection *conn;
     DBusConnection *dbus_conn;
@@ -264,8 +249,7 @@ int sbus_new_connection(TALLOC_CTX *ctx, struct tevent_context *ev,
         return EIO;
     }
 
-    ret = sbus_init_connection(ctx, ev, dbus_conn, intf,
-                               SBUS_CONN_TYPE_SHARED, &conn);
+    ret = sbus_init_connection(ctx, ev, dbus_conn, SBUS_CONN_TYPE_SHARED, &conn);
     if (ret != EOK) {
         /* FIXME: release resources */
     }
@@ -279,26 +263,7 @@ int sbus_new_connection(TALLOC_CTX *ctx, struct tevent_context *ev,
     return ret;
 }
 
-/*
- * sbus_conn_set_destructor
- * Configures a callback to clean up this connection when it
- * is finalized.
- * @param conn The sbus_connection created
- * when this connection was established
- * @param destructor The destructor function that should be
- * called when the connection is finalized. If passed NULL,
- * this will reset the connection to the default destructor.
- */
-void sbus_conn_set_destructor(struct sbus_connection *conn,
-                              sbus_conn_destructor_fn destructor)
-{
-    if (!conn) return;
-
-    conn->destructor = destructor;
-    /* TODO: Should we try to handle the talloc_destructor too? */
-}
-
-int sbus_default_connection_destructor(void *ctx)
+static int connection_destructor(void *ctx)
 {
     struct sbus_connection *conn;
     conn = talloc_get_type(ctx, struct sbus_connection);
@@ -350,11 +315,6 @@ void sbus_disconnect (struct sbus_connection *conn)
 
     conn->disconnect = 1;
 
-    /* Invoke the custom destructor, if it exists */
-    if (conn->destructor) {
-        conn->destructor(conn);
-    }
-
     /* Unregister object paths */
     sbus_unreg_object_paths(conn);
 
@@ -376,7 +336,7 @@ void sbus_disconnect (struct sbus_connection *conn)
                                              NULL, NULL, NULL);
 
     /* Finalize the connection */
-    sbus_default_connection_destructor(conn);
+    connection_destructor(conn);
 
     dbus_connection_unref(conn->dbus.conn);
     /* Unreferenced conn->dbus_conn *
@@ -465,16 +425,6 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
             result = DBUS_HANDLER_RESULT_HANDLED;
         }
     }
-    else {
-        /* Special case: check for Introspection request
-         * This is usually only useful for system bus connections
-         */
-        if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
-            strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0)
-        {
-            handler_fn = intf_p->intf->introspect_fn;
-        }
-    }
 
     if (handler_fn) {
         dbus_req = sbus_new_request(intf_p->conn, intf_p->intf, message);
@@ -482,7 +432,7 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
             ret = ENOMEM;
         } else {
             dbus_req->method = method;
-            ret = handler_fn(dbus_req);
+            ret = handler_fn(dbus_req, intf_p->intf->instance_data);
         }
         if (ret != EOK) {
             if (dbus_req)
@@ -496,6 +446,32 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
     return result;
 }
 
+struct sbus_interface *
+sbus_new_interface(TALLOC_CTX *mem_ctx,
+                   const char *object_path,
+                   struct sbus_vtable *iface_vtable,
+                   void *instance_data)
+{
+    struct sbus_interface *intf;
+
+    intf = talloc_zero(mem_ctx, struct sbus_interface);
+    if (intf == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Cannot allocate a new sbus_interface.\n");
+        return NULL;
+    }
+
+    intf->path = talloc_strdup(intf, object_path);
+    if (intf->path == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Cannot duplicate object path.\n");
+        talloc_free(intf);
+        return NULL;
+    }
+
+    intf->vtable = iface_vtable;
+    intf->instance_data = instance_data;
+    return intf;
+}
+
 /* Adds a new D-BUS path message handler to the connection
  * Note: this must be a unique path.
  */
@@ -569,16 +545,6 @@ static void sbus_unreg_object_paths(struct sbus_connection *conn)
     }
 }
 
-void sbus_conn_set_private_data(struct sbus_connection *conn, void *pvt_data)
-{
-    conn->pvt_data = pvt_data;
-}
-
-void *sbus_conn_get_private_data(struct sbus_connection *conn)
-{
-    return conn->pvt_data;
-}
-
 static void sbus_reconnect(struct tevent_context *ev,
                            struct tevent_timer *te,
                            struct timeval tv, void *data)
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index eca5c8380493754bb6fd55ef47f1740c5f095021..88230cfca4527c326c05efbe052d04b15dd00e88 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -44,9 +44,6 @@ struct sbus_connection {
     int connection_type;
     int disconnect;
 
-    sbus_conn_destructor_fn destructor;
-    void *pvt_data; /* Private data for this connection */
-
     /* dbus tables and handlers */
     struct sbus_interface_p *intf_list;
 
@@ -59,7 +56,6 @@ struct sbus_connection {
 
     /* server related stuff */
     char *symlink;
-    struct sbus_interface *server_intf;
     sbus_server_conn_init_fn srv_init_fn;
     void *srv_init_data;
 
diff --git a/src/sbus/sssd_dbus_server.c b/src/sbus/sssd_dbus_server.c
index 6973c8f2875f5df410278dea8be005b42dbb2ddc..5ab4ad0bb45ae0d0e3608187daac0452e0125b86 100644
--- a/src/sbus/sssd_dbus_server.c
+++ b/src/sbus/sssd_dbus_server.c
@@ -52,8 +52,7 @@ static void sbus_server_init_new_connection(DBusServer *dbus_server,
     }
 
     DEBUG(SSSDBG_FUNC_DATA,"Adding connection %p.\n", dbus_conn);
-    ret = sbus_init_connection(server, server->ev,
-                               dbus_conn, server->server_intf,
+    ret = sbus_init_connection(server, server->ev, dbus_conn,
                                SBUS_CONN_TYPE_PRIVATE, &conn);
     if (ret != 0) {
         dbus_connection_close(dbus_conn);
@@ -67,9 +66,6 @@ static void sbus_server_init_new_connection(DBusServer *dbus_server,
 
     /*
      * Initialize connection-specific features
-     * This may set a more detailed destructor, but
-     * the default destructor will always be chained
-     * to handle connection cleanup.
      * This function (or its callbacks) should also
      * set up connection-specific methods.
      */
@@ -185,7 +181,6 @@ remove_socket_symlink(const char *symlink_name)
 int sbus_new_server(TALLOC_CTX *mem_ctx,
                     struct tevent_context *ev,
                     const char *address,
-                    struct sbus_interface *intf,
                     bool use_symlink,
                     struct sbus_connection **_server,
                     sbus_server_conn_init_fn init_fn,
@@ -285,7 +280,6 @@ int sbus_new_server(TALLOC_CTX *mem_ctx,
     server->ev = ev;
     server->type = SBUS_SERVER;
     server->dbus.server = dbus_server;
-    server->server_intf = intf;
     server->srv_init_fn = init_fn;
     server->srv_init_data = init_pvt_data;
 
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index 146e18a850ad8dc322a379bdbb5c70ec95153277..decff339d35d1dcb2b8dcda006f31d72c28b0ac9 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -113,14 +113,14 @@ START_TEST(test_signals)
 END_TEST
 
 static int
-mock_move_universe(struct sbus_request *dbus_req)
+mock_move_universe(struct sbus_request *dbus_req, void *data)
 {
     /* not called */
     return 0;
 }
 
 static int
-mock_crash_now(struct sbus_request *dbus_req)
+mock_crash_now(struct sbus_request *dbus_req, void *data)
 {
     /* not called */
     return 0;
-- 
1.9.0

-------------- next part --------------
>From 8c3f0939c3e59d4d59f0f9adc874697685a93118 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at redhat.com>
Date: Tue, 18 Feb 2014 16:25:15 +0100
Subject: [PATCH 3/5] sbus: Make sbus_new_server() work for non-priveleged
 processes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

I'd like to use this during testing. We should check that the
socket ownership is the same as the process, rather than limiting
it to root.

Reviewed-by: Jakub Hrozek <jhrozek at redhat.com>
Reviewed-by: Pavel Březina <pbrezina at redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn at redhat.com>
(cherry picked from commit e35bff1cf25048a0dcafd6d8fdba60da82e88338)
---
 src/sbus/sssd_dbus_server.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/sbus/sssd_dbus_server.c b/src/sbus/sssd_dbus_server.c
index 5ab4ad0bb45ae0d0e3608187daac0452e0125b86..68dab85caad9fa6e8ebea0a4826e7f628b3da8e0 100644
--- a/src/sbus/sssd_dbus_server.c
+++ b/src/sbus/sssd_dbus_server.c
@@ -249,7 +249,7 @@ int sbus_new_server(TALLOC_CTX *mem_ctx,
 
     /* Both check_file and chmod can handle both the symlink and
      * the socket */
-    ret = check_file(filename, 0, 0, -1, CHECK_SOCK, &stat_buf, true);
+    ret = check_file(filename, getuid(), getgid(), -1, CHECK_SOCK, &stat_buf, true);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "check_file failed for [%s].\n", filename);
         ret = EIO;
-- 
1.9.0

-------------- next part --------------
>From 7bf14a1c8ac3a0d8cf2bd73170bc45427920e316 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at redhat.com>
Date: Tue, 18 Feb 2014 13:27:20 +0100
Subject: [PATCH 4/5] sbus_tests: Add some testing of dispatch and handler code
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This starts a DBus server with some handlers, and runs some method
calls against it.

Note that we don't use the codegen in the sbus_tests, as we sorta
want to test this non-codegen related functionality on its own before
we run the sbus_codegen_tests.

Reviewed-by: Jakub Hrozek <jhrozek at redhat.com>
Reviewed-by: Pavel Březina <pbrezina at redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn at redhat.com>

(cherry picked from commit f5e47e1d65f80ffdb1893feab18583a74d661214)

Conflicts:
	Makefile.am
---
 Makefile.am             |  11 +++
 src/tests/common.h      |  15 ++++
 src/tests/common_dbus.c | 198 +++++++++++++++++++++++++++++++++++++++++
 src/tests/sbus_tests.c  | 231 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 455 insertions(+)
 create mode 100644 src/tests/common_dbus.c
 create mode 100644 src/tests/sbus_tests.c

diff --git a/Makefile.am b/Makefile.am
index 01d199ace430ea42e7af1003eb0eb8498243b30d..79ab0fda5abb2612ce69388351b1225c154404ad 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -134,6 +134,7 @@ if HAVE_CHECK
         ipa_hbac-tests \
         sss_idmap-tests \
         responder_socket_access-tests \
+        sbus_tests \
         sbus_codegen_tests
 
 if BUILD_SSH
@@ -1308,6 +1309,16 @@ krb5_child_test_LDADD = \
     $(SSSD_INTERNAL_LTLIBS) \
     libsss_test_common.la
 
+sbus_tests_SOURCES = \
+   src/tests/common_dbus.c \
+   src/tests/sbus_tests.c
+sbus_tests_CFLAGS = \
+    $(CHECK_CFLAGS)
+sbus_tests_LDADD = \
+    $(SSSD_INTERNAL_LTLIBS) \
+    $(SSSD_LIBS) \
+    $(CHECK_LIBS)
+
 sbus_codegen_tests_SOURCES = \
    src/tests/sbus_codegen_tests.c \
    src/tests/sbus_codegen_tests_generated.c \
diff --git a/src/tests/common.h b/src/tests/common.h
index 931e603c1c59c7a73434b344cb1633faf37bf83c..ba3b3a7490ec5bd0e75c5f2f66c39542ca0c37ee 100644
--- a/src/tests/common.h
+++ b/src/tests/common.h
@@ -100,4 +100,19 @@ int test_ev_loop(struct sss_test_ctx *tctx);
 
 bool ldb_modules_path_is_set(void);
 
+DBusConnection *
+test_dbus_setup_mock(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *loop,
+                     sbus_server_conn_init_fn init_fn,
+                     void *init_pvt_data);
+
+DBusMessage *
+test_dbus_call_sync(DBusConnection *conn,
+                    const char *object_path,
+                    const char *interface,
+                    const char *method,
+                    DBusError *error,
+                    int first_arg_type,
+                    ...);
+
 #endif /* !__TESTS_COMMON_H__ */
diff --git a/src/tests/common_dbus.c b/src/tests/common_dbus.c
new file mode 100644
index 0000000000000000000000000000000000000000..3117c080dc3106517bee933a458583f35b04fa63
--- /dev/null
+++ b/src/tests/common_dbus.c
@@ -0,0 +1,198 @@
+/*
+   SSSD
+
+   Common utilities for dbus based tests.
+
+   Authors:
+        Stef Walter <stefw at redhat.com>
+
+   Copyright (C) Red Hat, Inc 2014
+
+   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 "config.h"
+
+#include <stdio.h>
+#include "tests/common.h"
+
+struct mock_server {
+    char *temp_dir;
+    char *dbus_address;
+    pid_t pid;
+    DBusConnection *client;
+
+    /* Used for synchronization */
+    int sync_fds[2];
+
+    /* Only used during init */
+    sbus_server_conn_init_fn init_fn;
+    void *init_pvt_data;
+};
+
+/*
+ * If you think we're going to do full error propagation during tests ...
+ * you're going to have a bad time (reading this code)
+ */
+#define verify_eq(x, y) \
+    do { if ((x) != (y)) { fprintf(stderr, "failed: %s == %s\n", #x, #y); abort(); } } while (0)
+#define verify_neq(x, y) \
+    do { if ((x) == (y)) { fprintf(stderr, "failed: %s != %s\n", #x, #y); abort(); } } while (0)
+
+static int
+mock_server_cleanup(struct mock_server *mock)
+{
+    int child_status;
+    const char *file;
+    struct stat sb;
+
+    dbus_connection_close(mock->client);
+    dbus_connection_unref(mock->client);
+
+    /* Tell the server thread to quit */
+    verify_eq (write(mock->sync_fds[0], "X", 1), 1);
+
+    /* Wait for the server child, it always returns mock */
+    verify_eq (waitpid(mock->pid, &child_status, 0), mock->pid);
+    verify_eq (child_status, 0);
+
+    file = strchr(mock->dbus_address, '/');
+    if (stat(file, &sb) == 0) {
+        verify_eq (unlink(file), 0);
+    }
+    verify_eq (rmdir(mock->temp_dir), 0);
+
+    return EOK;
+}
+
+static int
+on_accept_connection(struct sbus_connection *conn,
+                     void *data)
+{
+    struct mock_server *mock = data;
+
+    verify_eq (mock->init_fn(conn, mock->init_pvt_data), EOK);
+
+    /* Synchronization point: test_dbus_setup_mock() should return */
+    verify_eq (write(mock->sync_fds[1], "X", 1), 1);
+
+    return EOK;
+}
+
+static void
+on_sync_fd_written(struct tevent_context *loop,
+                   struct tevent_fd *fde,
+                   uint16_t flags,
+                   void *data)
+{
+    bool *stop_server = data;
+    *stop_server = true;
+}
+
+static void
+mock_server_child(void *data)
+{
+    struct mock_server *mock = data;
+    struct tevent_context *loop;
+    struct sbus_connection *server;
+    bool stop_server = false;
+    TALLOC_CTX *ctx;
+
+    ctx = talloc_new(NULL);
+    loop = tevent_context_init(ctx);
+
+    verify_eq (sbus_new_server(ctx, loop, mock->dbus_address, false,
+                               &server, on_accept_connection, mock), EOK);
+
+    tevent_add_fd(loop, ctx, mock->sync_fds[1], TEVENT_FD_READ,
+                  on_sync_fd_written, &stop_server);
+
+    /* Synchronization point: test_dbus_setup_mock() should connect */
+    verify_eq (write(mock->sync_fds[1], "X", 1), 1);
+
+    /* Do the loop */
+    while(!stop_server) {
+        verify_eq (tevent_loop_once(loop), 0);
+    }
+
+    /* TODO: sbus doesn't support cleanup of a server */
+
+    talloc_free(ctx);
+}
+
+struct DBusConnection *
+test_dbus_setup_mock(TALLOC_CTX *mem_ctx,
+                     struct tevent_context *loop,
+                     sbus_server_conn_init_fn init_fn,
+                     void *init_pvt_data)
+{
+    struct mock_server *mock;
+    char dummy;
+
+    mock = talloc_zero(mem_ctx, struct mock_server);
+    talloc_set_destructor(mock, mock_server_cleanup);
+    mock->init_fn = init_fn;
+    mock->init_pvt_data = init_pvt_data;
+
+    mock->temp_dir = mkdtemp(talloc_strdup(mock, "/tmp/sssd-dbus-tests.XXXXXX"));
+    verify_neq (mock->temp_dir, NULL);
+    mock->dbus_address = talloc_asprintf(mock, "unix:path=%s/sbus", mock->temp_dir);
+    verify_neq (mock->dbus_address, NULL);
+
+    /* We use an fd pair as a synchronization device, integrates with tevent well */
+    verify_eq (socketpair(PF_LOCAL, SOCK_STREAM, 0, mock->sync_fds), 0);
+
+    /* Run the dbus server in a child process */
+    mock->pid = fork();
+    if (mock->pid == 0) {
+        mock_server_child(mock);
+        _exit(0);
+    }
+
+    verify_neq (mock->pid, -1);
+
+    /* Synchronization point: wait for sync point in mock_server_child */
+    verify_eq (read(mock->sync_fds[0], &dummy, 1), 1);
+
+    /* Open a shared D-BUS connection to the address */
+    mock->client = dbus_connection_open_private(mock->dbus_address, NULL);
+    verify_neq (mock->client, NULL);
+
+    /* Synchronization point: wait for sync point in on_accept_connection */
+    verify_eq (read(mock->sync_fds[0], &dummy, 1), 1);
+
+    return mock->client;
+}
+
+DBusMessage *
+test_dbus_call_sync(DBusConnection *conn, const char *object_path,
+                    const char *interface, const char *method,
+                    DBusError *error, int first_arg_type, ...)
+{
+    DBusMessage *message;
+    DBusMessage *reply;
+    va_list va;
+
+    message = dbus_message_new_method_call(NULL, object_path, interface, method);
+    verify_neq(message, NULL);
+
+    va_start(va, first_arg_type);
+    verify_eq(dbus_message_append_args_valist(message, first_arg_type, va), TRUE);
+    va_end(va);
+
+    reply = dbus_connection_send_with_reply_and_block(conn, message, -1, error);
+    dbus_message_unref(message);
+
+    return reply;
+}
diff --git a/src/tests/sbus_tests.c b/src/tests/sbus_tests.c
new file mode 100644
index 0000000000000000000000000000000000000000..7290fe7dbf9d6b0811afbc3b27d3500cff63761a
--- /dev/null
+++ b/src/tests/sbus_tests.c
@@ -0,0 +1,231 @@
+/*
+   SSSD
+
+   sbus_codegen tests.
+
+   Authors:
+        Stef Walter <stefw at redhat.com>
+
+   Copyright (C) Red Hat, Inc 2014
+
+   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 <stdlib.h>
+#include <check.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <popt.h>
+
+#include "common.h"
+
+#include "sbus/sssd_dbus.h"
+#include "sbus/sssd_dbus_meta.h"
+#include "util/util_errors.h"
+
+/*
+ * Although one would normally rely on the codegen to generate these
+ * structures, we want to test this functionality *before* we test
+ * the codegen in sbus_codegen_tests ... so these are hand rolled.
+ */
+
+#define PILOT_IFACE "test.Pilot"
+#define PILOT_BLINK "Blink"
+
+/* our vtable */
+struct pilot_vtable {
+    struct sbus_vtable vtable;
+    sbus_msg_handler_fn Blink;
+};
+
+const struct sbus_method_meta pilot_methods[] = {
+    {
+        PILOT_BLINK, /* method name */
+        NULL, /* in args: manually parsed */
+        NULL, /* out args: manually parsed */
+        offsetof(struct pilot_vtable, Blink),
+    },
+    { NULL, }
+};
+
+const struct sbus_interface_meta pilot_meta = {
+    PILOT_IFACE, /* name */
+    pilot_methods,
+    NULL, /* no signals */
+    NULL, /* no properties */
+};
+
+static int blink_handler(struct sbus_request *req, void *data)
+{
+    DBusError error = DBUS_ERROR_INIT;
+    const char *path;
+    dbus_int32_t duration = 0;
+    dbus_bool_t crashed;
+
+    ck_assert(req->intf->vtable->meta == &pilot_meta);
+    ck_assert(data != NULL);
+    ck_assert(data == req->intf->instance_data);
+
+    path = dbus_message_get_path(req->message);
+    ck_assert_str_eq(req->intf->path, path);
+
+    if (strcmp(path, "/test/fry") == 0) {
+        ck_assert_str_eq(data, "Don't crash");
+    } else if (strcmp(path, "/test/leela") == 0) {
+        ck_assert_str_eq(data, "Crash into the billboard");
+    } else {
+        ck_abort();
+    }
+
+    if (!dbus_message_get_args (req->message, &error,
+                                DBUS_TYPE_INT32, &duration,
+                                DBUS_TYPE_INVALID)) {
+        sbus_request_fail_and_finish(req, &error);
+        dbus_error_free(&error);
+        return EOK;
+    }
+
+    /* Pilot crashes when eyes closed too long */
+    crashed = (duration > 5);
+
+    return sbus_request_return_and_finish(req,
+                                          DBUS_TYPE_BOOLEAN, &crashed,
+                                          DBUS_TYPE_INVALID);
+}
+
+struct pilot_vtable pilot_impl = {
+    { &pilot_meta, 0 },
+    .Blink = blink_handler,
+};
+
+static int pilot_test_server_init(struct sbus_connection *server, void *unused)
+{
+    int ret;
+
+    ret = sbus_conn_add_interface(server,
+                                  sbus_new_interface(server, "/test/leela",
+                                                     &pilot_impl.vtable,
+                                                     "Crash into the billboard"));
+    ck_assert_int_eq(ret, EOK);
+
+
+    ret = sbus_conn_add_interface(server,
+                                  sbus_new_interface(server, "/test/fry",
+                                                     &pilot_impl.vtable,
+                                                     "Don't crash"));
+    ck_assert_int_eq(ret, EOK);
+
+    return EOK;
+}
+
+START_TEST(test_raw_handler)
+{
+    TALLOC_CTX *ctx;
+    DBusConnection *client;
+    DBusError error = DBUS_ERROR_INIT;
+    DBusMessage *reply;
+    dbus_bool_t crashed;
+    dbus_int32_t duration;
+
+    ctx = talloc_new(NULL);
+    client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
+
+    /* Leela crashes with a duration higher than 5 */
+    duration = 10;
+    reply = test_dbus_call_sync(client,
+                                "/test/leela",
+                                PILOT_IFACE,
+                                PILOT_BLINK,
+                                &error,
+                                DBUS_TYPE_INT32, &duration,
+                                DBUS_TYPE_INVALID);
+    ck_assert(reply != NULL);
+    ck_assert(!dbus_error_is_set(&error));
+    ck_assert(dbus_message_get_args(reply, NULL,
+                                    DBUS_TYPE_BOOLEAN, &crashed,
+                                    DBUS_TYPE_INVALID));
+    dbus_message_unref (reply);
+    ck_assert(crashed == true);
+
+    /* Fry daesn't crash with a duration lower than 5 */
+    duration = 1;
+    reply = test_dbus_call_sync(client,
+                                "/test/fry",
+                                PILOT_IFACE,
+                                PILOT_BLINK,
+                                &error,
+                                DBUS_TYPE_INT32, &duration,
+                                DBUS_TYPE_INVALID);
+    ck_assert(reply != NULL);
+    ck_assert(!dbus_error_is_set(&error));
+    ck_assert(dbus_message_get_args(reply, NULL,
+                                    DBUS_TYPE_BOOLEAN, &crashed,
+                                    DBUS_TYPE_INVALID));
+    dbus_message_unref (reply);
+    ck_assert(crashed == FALSE);
+
+    talloc_free(ctx);
+}
+END_TEST
+
+TCase *create_sbus_tests(void)
+{
+    TCase *tc = tcase_create("tests");
+
+    tcase_add_test(tc, test_raw_handler);
+
+    return tc;
+}
+
+Suite *create_suite(void)
+{
+    Suite *s = suite_create("sbus");
+    suite_add_tcase(s, create_sbus_tests());
+    return s;
+}
+
+int main(int argc, const char *argv[])
+{
+    int opt;
+    poptContext pc;
+    int failure_count;
+    Suite *suite;
+    SRunner *sr;
+
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        POPT_TABLEEND
+    };
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while ((opt = poptGetNextOpt(pc)) != -1) {
+        switch (opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+    poptFreeContext(pc);
+
+    suite = create_suite();
+    sr = srunner_create(suite);
+    srunner_set_fork_status(sr, CK_NOFORK);
+    /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
+    srunner_run_all(sr, CK_ENV);
+    failure_count = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    return (failure_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
-- 
1.9.0

-------------- next part --------------
>From 966205cdcd3286128f2693399c0d31ad0ea078d2 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at redhat.com>
Date: Fri, 21 Feb 2014 16:59:48 +0100
Subject: [PATCH 5/5] sbus: Add the sbus_request_parse_or_finish() method
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Some DBus types returned from dbus_message_get_args() require memory
to be released when done. We automatically attach these to the talloc
struct sbus_request memory context in this function.

This accepts varargs similar to dbus_message_get_args(), which are
rather awkward. However instead of reworking them completely, future
generated marshalling code will replace most uses of these varargs.

If parsing the dbus message fails, then it responds to the DBus caller
with an appropriate error such as o.f.D.Error.InvalidArgs. In these
cases (ie: when it returns FALSE) the sbus_request is finished.

Migrated some, but not all, uses of dbus_message_get_args() to the
new function. Some instances have uncommon semantics such as terminating
the connection upon failure to parse a message.

Reviewed-by: Jakub Hrozek <jhrozek at redhat.com>
Reviewed-by: Pavel Březina <pbrezina at redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn at redhat.com>
(cherry picked from commit 06b7bc8ca2e005ed510210d3b8dee16afbabbcc9)
---
 src/providers/data_provider_be.c |  72 ++++++++------------------
 src/providers/proxy/proxy_init.c |  19 ++-----
 src/responder/nss/nsssrv.c       |  23 +++------
 src/sbus/sssd_dbus.h             |  49 ++++++++++++++++++
 src/sbus/sssd_dbus_request.c     | 106 +++++++++++++++++++++++++++++++++++++++
 src/tests/sbus_tests.c           |  99 ++++++++++++++++++++++++++++++++++++
 6 files changed, 287 insertions(+), 81 deletions(-)

diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index 3c2dda230dee02f2bfa44e7d96eb63d8c5d308b4..ac703b821d1f1bb84542743e5ac03ee0a7058f70 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -558,7 +558,6 @@ static int be_get_subdomains(struct sbus_request *dbus_req, void *user_data)
     struct be_subdom_req *req;
     struct be_req *be_req = NULL;
     struct be_client *becli;
-    DBusError dbus_error;
     dbus_bool_t force;
     char *domain_hint;
     dbus_uint16_t err_maj;
@@ -569,17 +568,11 @@ static int be_get_subdomains(struct sbus_request *dbus_req, void *user_data)
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
-    dbus_error_init(&dbus_error);
-
-    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
-                                DBUS_TYPE_BOOLEAN, &force,
-                                DBUS_TYPE_STRING, &domain_hint,
-                                DBUS_TYPE_INVALID);
-    if (!ret) {
-        DEBUG(SSSDBG_CRIT_FAILURE,"Failed, to parse message!\n");
-        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
-        return EIO;
-    }
+    if (!sbus_request_parse_or_finish(dbus_req,
+                                      DBUS_TYPE_BOOLEAN, &force,
+                                      DBUS_TYPE_STRING, &domain_hint,
+                                      DBUS_TYPE_INVALID))
+        return EOK; /* handled */
 
     /* return an error if corresponding backend target is not configured */
     if (becli->bectx->bet_info[BET_SUBDOMAINS].bet_ops == NULL) {
@@ -1036,7 +1029,6 @@ static int be_get_account_info(struct sbus_request *dbus_req, void *user_data)
     struct be_acct_req *req;
     struct be_req *be_req;
     struct be_client *becli;
-    DBusError dbus_error;
     uint32_t type;
     char *filter;
     char *domain;
@@ -1051,19 +1043,13 @@ static int be_get_account_info(struct sbus_request *dbus_req, void *user_data)
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
-    dbus_error_init(&dbus_error);
-
-    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
-                                DBUS_TYPE_UINT32, &type,
-                                DBUS_TYPE_UINT32, &attr_type,
-                                DBUS_TYPE_STRING, &filter,
-                                DBUS_TYPE_STRING, &domain,
-                                DBUS_TYPE_INVALID);
-    if (!ret) {
-        DEBUG(SSSDBG_CRIT_FAILURE,"Failed, to parse message!\n");
-        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
-        return EIO;
-    }
+    if (!sbus_request_parse_or_finish(dbus_req,
+                                      DBUS_TYPE_UINT32, &type,
+                                      DBUS_TYPE_UINT32, &attr_type,
+                                      DBUS_TYPE_STRING, &filter,
+                                      DBUS_TYPE_STRING, &domain,
+                                      DBUS_TYPE_INVALID))
+        return EOK; /* handled */
 
     DEBUG(SSSDBG_CONF_SETTINGS,
           "Got request for [%u][%d][%s]\n", type, attr_type, filter);
@@ -1607,7 +1593,6 @@ static void be_autofs_handler_callback(struct be_req *req,
 
 static int be_autofs_handler(struct sbus_request *dbus_req, void *user_data)
 {
-    DBusError dbus_error;
     struct be_client *be_cli = NULL;
     struct be_req *be_req = NULL;
     struct be_autofs_req *be_autofs_req = NULL;
@@ -1627,17 +1612,11 @@ static int be_autofs_handler(struct sbus_request *dbus_req, void *user_data)
         return EINVAL;
     }
 
-    dbus_error_init(&dbus_error);
-
-    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
-                                DBUS_TYPE_UINT32, &type,
-                                DBUS_TYPE_STRING, &filter,
-                                DBUS_TYPE_INVALID);
-    if (!ret) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse message!\n");
-        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
-        return EIO;
-    }
+    if (!sbus_request_parse_or_finish(dbus_req,
+                                      DBUS_TYPE_UINT32, &type,
+                                      DBUS_TYPE_STRING, &filter,
+                                      DBUS_TYPE_INVALID))
+        return EOK; /* handled */
 
     /* If we are offline and fast reply was requested
      * return offline immediately
@@ -1818,7 +1797,6 @@ static int be_host_handler(struct sbus_request *dbus_req, void *user_data)
     struct be_host_req *req;
     struct be_req *be_req;
     struct be_client *becli;
-    DBusError dbus_error;
     uint32_t flags;
     char *filter;
     int ret;
@@ -1831,17 +1809,11 @@ static int be_host_handler(struct sbus_request *dbus_req, void *user_data)
     becli = talloc_get_type(user_data, struct be_client);
     if (!becli) return EINVAL;
 
-    dbus_error_init(&dbus_error);
-
-    ret = dbus_message_get_args(dbus_req->message, &dbus_error,
-                                DBUS_TYPE_UINT32, &flags,
-                                DBUS_TYPE_STRING, &filter,
-                                DBUS_TYPE_INVALID);
-    if (!ret) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse message!\n");
-        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
-        return EIO;
-    }
+    if (!sbus_request_parse_or_finish(dbus_req,
+                                      DBUS_TYPE_UINT32, &flags,
+                                      DBUS_TYPE_STRING, &filter,
+                                      DBUS_TYPE_INVALID))
+        return EOK; /* request finished */
 
     DEBUG(SSSDBG_TRACE_LIBS,
           "Got request for [%u][%s]\n", flags, filter);
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
index 0206ec15b670e1763102ee2d99e18918a56c56e7..dd1b75826fbfc384dd37ba659a8653547cc35bcf 100644
--- a/src/providers/proxy/proxy_init.c
+++ b/src/providers/proxy/proxy_init.c
@@ -397,10 +397,8 @@ static int client_registration(struct sbus_request *dbus_req, void *data)
     dbus_uint16_t version = DATA_PROVIDER_VERSION;
     struct sbus_connection *conn;
     struct proxy_client *proxy_cli;
-    DBusError dbus_error;
     dbus_uint16_t cli_ver;
     uint32_t cli_id;
-    dbus_bool_t dbret;
     int hret;
     hash_key_t key;
     hash_value_t value;
@@ -421,19 +419,12 @@ static int client_registration(struct sbus_request *dbus_req, void *data)
           "Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout);
     talloc_zfree(proxy_cli->timeout);
 
-    dbus_error_init(&dbus_error);
-
-    dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
-                                  DBUS_TYPE_UINT16, &cli_ver,
-                                  DBUS_TYPE_UINT32, &cli_id,
-                                  DBUS_TYPE_INVALID);
-    if (!dbret) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Failed to parse message, killing connection\n");
-        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
+    if (!sbus_request_parse_or_finish(dbus_req,
+                                      DBUS_TYPE_UINT16, &cli_ver,
+                                      DBUS_TYPE_UINT32, &cli_id,
+                                      DBUS_TYPE_INVALID)) {
         sbus_disconnect(conn);
-        /* FIXME: should we just talloc_zfree(conn) ? */
-        return EIO;
+        return EOK; /* handled */
     }
 
     DEBUG(SSSDBG_FUNC_DATA, "Proxy client [%"PRIu32"] connected\n", cli_id);
diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
index 5e62377229de49034c5d80e87495a5d6dedf3229..c6e7cb402d5bade600b36442d096d14d505b30a9 100644
--- a/src/responder/nss/nsssrv.c
+++ b/src/responder/nss/nsssrv.c
@@ -311,28 +311,17 @@ static int nss_memcache_initgr_check(struct sbus_request *dbus_req, void *data)
 {
     struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
     struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
-    DBusError dbus_error;
-    dbus_bool_t dbret;
     char *user;
     char *domain;
     uint32_t *groups;
     int gnum;
 
-    dbus_error_init(&dbus_error);
-
-    dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
-                                  DBUS_TYPE_STRING, &user,
-                                  DBUS_TYPE_STRING, &domain,
-                                  DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
-                                  &groups, &gnum,
-                                  DBUS_TYPE_INVALID);
-
-    if (!dbret) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse message!\n");
-        if (dbus_error_is_set(&dbus_error)) {
-            dbus_error_free(&dbus_error);
-        }
-        return EIO;
+    if (!sbus_request_parse_or_finish(dbus_req,
+                                      DBUS_TYPE_STRING, &user,
+                                      DBUS_TYPE_STRING, &domain,
+                                      DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &groups, &gnum,
+                                      DBUS_TYPE_INVALID)) {
+        return EOK; /* handled */
     }
 
     DEBUG(SSSDBG_TRACE_LIBS,
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index ef728bd30e6b52cb18bd5d68f0d4f4e759358eca..3bf70c8cceaeed45d57dad802d196c931d7f030d 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -252,4 +252,53 @@ int sbus_request_return_and_finish(struct sbus_request *dbus_req,
 int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
                                  const DBusError *error);
 
+/*
+ * Parse a DBus method call request.
+ *
+ * If parsing the method call message does not succeed, then an error is
+ * sent to the DBus caller and the request is finished. If this function
+ * returns false then @request is no longer valid.
+ *
+ * This also means if this method returns false within a handler, you should
+ * return EOK from the handler. The message has been handled, appropriate
+ * logs have been written, and everything should just move on.
+ *
+ * If the method call does not match the expected arguments, then a
+ * org.freedesktop.DBus.Error.InvalidArgs is returned to the caller as
+ * expected.
+ *
+ * The variable arguments are (unfortunately) formatted exactly the same
+ * as those of the dbus_message_get_args() function. Documented here:
+ *
+ * http://dbus.freedesktop.org/doc/api/html/group__DBusMessage.html
+ *
+ * Exception: You don't need to free string arrays returned by this
+ * function. They are automatically talloc parented to the request memory
+ * context and can be used until the request has been finished.
+ *
+ * Important: don't pass int or bool or such types as values to this
+ * function. That's not portable. Use actual dbus types. You must also pass
+ * pointers as the values:
+ *
+ *    dbus_bool_t val1;
+ *    dbus_int32_t val2;
+ *    ret = sbus_request_parse_or_finish(request,
+ *                                       DBUS_TYPE_BOOLEAN, &val1,
+ *                                       DBUS_TYPE_INT32, &val2,
+ *                                       DBUS_TYPE_INVALID);
+ *
+ * To pass arrays to this function, use the following syntax. Never
+ * pass actual C arrays with [] syntax to this function. The C standard is
+ * rather vague with C arrays and varargs, and it just plain doesn't work.
+ *
+ *    int count; // yes, a plain int
+ *    const char **array;
+ *    ret = sbus_request_parse_or_finish(request,
+ *                                       DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, &count,
+ *                                       DBUS_TYPE_INVALID);
+ */
+bool sbus_request_parse_or_finish(struct sbus_request *request,
+                                  int first_arg_type,
+                                  ...);
+
 #endif /* _SSSD_DBUS_H_*/
diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c
index 973089c4bbc5d766edfe5792a366d0548c3c3855..c45f3a9fdb7204a2f296f1a0870c1275aa42e0d8 100644
--- a/src/sbus/sssd_dbus_request.c
+++ b/src/sbus/sssd_dbus_request.c
@@ -110,3 +110,109 @@ int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
     dbus_message_unref(reply);
     return ret;
 }
+
+struct array_arg {
+    char **dbus_array;
+};
+
+static int array_arg_destructor(struct array_arg *arg)
+{
+    dbus_free_string_array(arg->dbus_array);
+    return 0;
+}
+
+static bool
+parent_dbus_string_arrays(struct sbus_request *request, int first_arg_type,
+                          va_list va)
+{
+    struct array_arg *array_arg;
+    int arg_type;
+    void **arg_ptr;
+
+    /*
+     * Here we iterate through the entire thing again and look for
+     * things we need to fix allocation for. Normally certain types
+     * returned from dbus_message_get_args() and friends require
+     * later freeing. We tie those to the talloc context here.
+     *
+     * The list of argument has already been validated by the previous
+     * dbus_message_get_args() call, so we can be cheap.
+     */
+
+    arg_type = first_arg_type;
+    while (arg_type != DBUS_TYPE_INVALID) {
+
+        if (arg_type == DBUS_TYPE_ARRAY) {
+            arg_type = va_arg(va, int);     /* the array element type */
+            arg_ptr = va_arg(va, void **);  /* the array elements */
+            va_arg(va, int *);              /* the array length */
+
+            /* Arrays of these things need to be freed */
+            if (arg_type == DBUS_TYPE_STRING ||
+                arg_type == DBUS_TYPE_OBJECT_PATH ||
+                arg_type == DBUS_TYPE_SIGNATURE) {
+
+                array_arg = talloc_zero(request, struct array_arg);
+                if(array_arg == NULL) {
+                    /* no kidding ... */
+                    DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory while trying not to leak memory\n");
+                    return false;
+                }
+
+                array_arg->dbus_array = *arg_ptr;
+                talloc_set_destructor(array_arg, array_arg_destructor);
+            }
+
+        /* A non array argument */
+        } else {
+            arg_ptr = va_arg(va, void**);
+        }
+
+        /* The next type */
+        arg_type = va_arg(va, int);
+    }
+
+    return true;
+}
+
+bool
+sbus_request_parse_or_finish(struct sbus_request *request,
+                             int first_arg_type,
+                             ...)
+{
+    DBusError error = DBUS_ERROR_INIT;
+    bool ret = true;
+    va_list va2;
+    va_list va;
+
+    va_start(va, first_arg_type);
+    va_copy(va2, va);
+
+    if (dbus_message_get_args_valist(request->message, &error,
+                                     first_arg_type, va)) {
+        ret = parent_dbus_string_arrays (request, first_arg_type, va2);
+
+    } else {
+        /* Trying to send the error back to the caller in this case is a joke */
+        if (!dbus_error_is_set(&error) || dbus_error_has_name(&error, DBUS_ERROR_NO_MEMORY)) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory parsing DBus message\n");
+            sbus_request_finish(request, NULL);
+
+        /* Log other errors and send them back, this include o.f.d.InvalidArgs */
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE, "Couldn't parse DBus message %s.%s: %s\n",
+                  dbus_message_get_interface(request->message),
+                  dbus_message_get_member(request->message),
+                  error.message);
+            sbus_request_fail_and_finish(request, &error);
+        }
+
+        dbus_error_free(&error);
+        ret = false;
+    }
+
+    va_end(va2);
+    va_end(va);
+
+    return ret;
+}
diff --git a/src/tests/sbus_tests.c b/src/tests/sbus_tests.c
index 7290fe7dbf9d6b0811afbc3b27d3500cff63761a..b8cd4abb0d306d0b9dbf7896f0e1709c1dc7fd40 100644
--- a/src/tests/sbus_tests.c
+++ b/src/tests/sbus_tests.c
@@ -42,11 +42,13 @@
 
 #define PILOT_IFACE "test.Pilot"
 #define PILOT_BLINK "Blink"
+#define PILOT_EAT "Eat"
 
 /* our vtable */
 struct pilot_vtable {
     struct sbus_vtable vtable;
     sbus_msg_handler_fn Blink;
+    sbus_msg_handler_fn Eat;
 };
 
 const struct sbus_method_meta pilot_methods[] = {
@@ -56,6 +58,12 @@ const struct sbus_method_meta pilot_methods[] = {
         NULL, /* out args: manually parsed */
         offsetof(struct pilot_vtable, Blink),
     },
+    {
+        PILOT_EAT, /* method name */
+        NULL, /* in args: manually parsed */
+        NULL, /* out args: manually parsed */
+        offsetof(struct pilot_vtable, Eat),
+    },
     { NULL, }
 };
 
@@ -104,9 +112,35 @@ static int blink_handler(struct sbus_request *req, void *data)
                                           DBUS_TYPE_INVALID);
 }
 
+static int eat_handler(struct sbus_request *req, void *data)
+{
+    dbus_int32_t integer;
+    dbus_bool_t boolean;
+    const char **array;
+    int count;
+
+    if (!sbus_request_parse_or_finish (req,
+                                       DBUS_TYPE_INT32, &integer,
+                                       DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, &count,
+                                       DBUS_TYPE_BOOLEAN, &boolean,
+                                       DBUS_TYPE_INVALID)) {
+        return EOK; /* handled */
+    }
+
+    ck_assert_int_eq(integer, 5);
+    ck_assert(boolean == TRUE);
+    ck_assert_int_eq(count, 3);
+    ck_assert_str_eq(array[0], "one");
+    ck_assert_str_eq(array[1], "two");
+    ck_assert_str_eq(array[2], "three");
+
+    return sbus_request_return_and_finish(req, DBUS_TYPE_INVALID);
+}
+
 struct pilot_vtable pilot_impl = {
     { &pilot_meta, 0 },
     .Blink = blink_handler,
+    .Eat = eat_handler,
 };
 
 static int pilot_test_server_init(struct sbus_connection *server, void *unused)
@@ -179,11 +213,76 @@ START_TEST(test_raw_handler)
 }
 END_TEST
 
+START_TEST(test_request_parse_ok)
+{
+    const char *args[] = { "one", "two", "three" };
+    const char **array;
+    TALLOC_CTX *ctx;
+    DBusConnection *client;
+    DBusError error = DBUS_ERROR_INIT;
+    DBusMessage *reply;
+    dbus_bool_t boolean;
+    dbus_int32_t integer;
+    int count;
+
+    ctx = talloc_new(NULL);
+    client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
+
+    boolean = TRUE;
+    integer = 5;
+    count = 3;
+    array = args;
+    reply = test_dbus_call_sync(client,
+                                "/test/leela",
+                                PILOT_IFACE,
+                                PILOT_EAT,
+                                &error,
+                                DBUS_TYPE_INT32, &integer,
+                                DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, count,
+                                DBUS_TYPE_BOOLEAN, &boolean,
+                                DBUS_TYPE_INVALID);
+    ck_assert(reply != NULL);
+    ck_assert(!dbus_error_is_set(&error));
+    ck_assert(dbus_message_get_args(reply, NULL,
+                                    DBUS_TYPE_INVALID));
+    dbus_message_unref (reply);
+
+    talloc_free(ctx);
+}
+END_TEST
+
+START_TEST(test_request_parse_bad_args)
+{
+    TALLOC_CTX *ctx;
+    DBusConnection *client;
+    DBusError error = DBUS_ERROR_INIT;
+    DBusMessage *reply;
+
+    ctx = talloc_new(NULL);
+    client = test_dbus_setup_mock(ctx, NULL, pilot_test_server_init, NULL);
+
+    reply = test_dbus_call_sync(client,
+                                "/test/leela",
+                                PILOT_IFACE,
+                                PILOT_EAT,
+                                &error,
+                                DBUS_TYPE_INVALID); /* bad agruments */
+    ck_assert(reply == NULL);
+    ck_assert(dbus_error_is_set(&error));
+    ck_assert(dbus_error_has_name(&error, DBUS_ERROR_INVALID_ARGS));
+    dbus_error_free(&error);
+
+    talloc_free(ctx);
+}
+END_TEST
+
 TCase *create_sbus_tests(void)
 {
     TCase *tc = tcase_create("tests");
 
     tcase_add_test(tc, test_raw_handler);
+    tcase_add_test(tc, test_request_parse_ok);
+    tcase_add_test(tc, test_request_parse_bad_args);
 
     return tc;
 }
-- 
1.9.0



More information about the sssd-devel mailing list