summaryrefslogtreecommitdiffstats
path: root/src/sbus
diff options
context:
space:
mode:
Diffstat (limited to 'src/sbus')
-rw-r--r--src/sbus/sssd_dbus_connection.c35
-rw-r--r--src/sbus/sssd_dbus_introspect.c330
-rw-r--r--src/sbus/sssd_dbus_private.h6
3 files changed, 368 insertions, 3 deletions
diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
index 150b5469e..64777fbe8 100644
--- a/src/sbus/sssd_dbus_connection.c
+++ b/src/sbus/sssd_dbus_connection.c
@@ -378,6 +378,8 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
const struct sbus_interface_meta *interface;
struct sbus_request *dbus_req = NULL;
sbus_msg_handler_fn handler_fn = NULL;
+ void *handler_data = NULL; /* Must be a talloc pointer! */
+ struct sbus_introspect_ctx *ictx = NULL;
DBusHandlerResult result;
int ret;
@@ -425,19 +427,46 @@ DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
dbus_message_unref(reply);
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) {
+ DEBUG(SSSDBG_TRACE_LIBS, "Got introspection request\n");
+ ictx = talloc(intf_p->conn, struct sbus_introspect_ctx);
+ if (ictx == NULL) {
+ result = sbus_reply_internal_error(message, intf_p->conn);
+ } else {
+ handler_fn = sbus_introspect;
+ ictx->iface = interface;
+ handler_data = ictx;
+ }
+ }
}
if (handler_fn) {
dbus_req = sbus_new_request(intf_p->conn, intf_p->intf, message);
if (!dbus_req) {
+ talloc_zfree(handler_data);
ret = ENOMEM;
} else {
dbus_req->method = method;
- ret = handler_fn(dbus_req, intf_p->intf->instance_data);
+ if (handler_data) {
+ /* If the handler uses private instance data, make
+ * sure they go away when the request does
+ */
+ talloc_steal(dbus_req, handler_data);
+ } else {
+ /* If no custom handler data is set, pass on the
+ * interface data
+ */
+ handler_data = intf_p->intf->instance_data;
+ }
+ ret = handler_fn(dbus_req, handler_data);
}
if (ret != EOK) {
- if (dbus_req)
- talloc_free(dbus_req);
+ talloc_free(dbus_req);
result = sbus_reply_internal_error(message, intf_p->conn);
} else {
result = DBUS_HANDLER_RESULT_HANDLED;
diff --git a/src/sbus/sssd_dbus_introspect.c b/src/sbus/sssd_dbus_introspect.c
new file mode 100644
index 000000000..ffc1f4d38
--- /dev/null
+++ b/src/sbus/sssd_dbus_introspect.c
@@ -0,0 +1,330 @@
+/*
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2014 Red Hat
+
+ SBUS: Interface introspection
+
+ 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 <sys/time.h>
+#include <dbus/dbus.h>
+
+#include "util/util.h"
+#include "sbus/sssd_dbus.h"
+#include "sbus/sssd_dbus_private.h"
+#include "sbus/sssd_dbus_meta.h"
+
+#define SSS_INTROSPECT_DOCTYPE \
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+
+#define SSS_INTROSPECT_INTERFACE_INTROSPECTABLE \
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
+ " <method name=\"Introspect\">\n" \
+ " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " </interface>\n"
+
+
+struct introspect_ctx {
+ FILE *f;
+ char *buf;
+ size_t size;
+
+ const struct sbus_interface_meta *iface;
+};
+
+static int introspect_ctx_destructor(struct introspect_ctx *ictx)
+{
+ free(ictx->buf);
+ ictx->buf = NULL;
+ return 0;
+}
+
+static errno_t introspect_begin(struct introspect_ctx *ictx)
+{
+ errno_t ret;
+
+ ictx->f = open_memstream(&ictx->buf, &ictx->size);
+ if (ictx->f == NULL) {
+ return ENOMEM;
+ }
+
+ ret = fputs(SSS_INTROSPECT_DOCTYPE, ictx->f);
+ if (ret < 0) return EIO;
+ ret = fputs("<node>\n", ictx->f);
+ if (ret < 0) return EIO;
+
+ ret = fprintf(ictx->f, " <interface name=\"%s\">\n", ictx->iface->name);
+ if (ret <= 0) return EIO;
+
+ return EOK;
+}
+
+static errno_t introspect_add_arg(struct introspect_ctx *ictx,
+ const struct sbus_arg_meta *a,
+ const char *direction)
+{
+ errno_t ret;
+
+ ret = fprintf(ictx->f,
+ " <arg type=\"%s\" name=\"%s\"",
+ a->type, a->name);
+ if (ret <= 0) return EIO;
+
+ if (direction) {
+ ret = fprintf(ictx->f, " direction=\"%s\"", direction);
+ if (ret <= 0) return EIO;
+ }
+
+ ret = fprintf(ictx->f, "/>\n");
+ if (ret <= 0) return EIO;
+
+ return EOK;
+}
+
+#define introspect_add_in_arg(i, a) introspect_add_arg(i, a, "in");
+#define introspect_add_out_arg(i, a) introspect_add_arg(i, a, "out");
+#define introspect_add_sig_arg(i, a) introspect_add_arg(i, a, NULL);
+
+static errno_t introspect_add_meth(struct introspect_ctx *ictx,
+ const struct sbus_method_meta *m)
+{
+ errno_t ret;
+ int i;
+
+ ret = fprintf(ictx->f, " <method name=\"%s\">\n", m->name);
+ if (ret <= 0) return EIO;
+
+ if (m->in_args != NULL) {
+ for (i = 0; m->in_args[i].name != NULL; i++) {
+ ret = introspect_add_in_arg(ictx, &m->in_args[i]);
+ if (ret != EOK) {
+ continue;
+ }
+ }
+ }
+
+ if (m->out_args != NULL) {
+ for (i = 0; m->out_args[i].name != NULL; i++) {
+ ret = introspect_add_out_arg(ictx, &m->out_args[i]);
+ if (ret != EOK) {
+ continue;
+ }
+ }
+ }
+
+ ret = fputs(" </method>\n", ictx->f);
+ if (ret < 0) return EIO;
+
+ return EOK;
+}
+
+static errno_t introspect_add_methods(struct introspect_ctx *ictx)
+{
+ errno_t ret;
+ int i;
+
+ if (ictx->iface->methods == NULL) {
+ /* An interface with no methods */
+ return EOK;
+ }
+
+ for (i = 0; ictx->iface->methods[i].name != NULL; i++) {
+ ret = introspect_add_meth(ictx, &ictx->iface->methods[i]);
+ if (ret != EOK) {
+ continue;
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t introspect_add_sig(struct introspect_ctx *ictx,
+ const struct sbus_signal_meta *s)
+{
+ errno_t ret;
+ int i;
+
+ ret = fprintf(ictx->f, " <signal name=\"%s\">\n", s->name);
+ if (ret <= 0) return EIO;
+
+ if (s->args != NULL) {
+ for (i = 0; s->args[i].name != NULL; i++) {
+ ret = introspect_add_sig_arg(ictx, &s->args[i]);
+ if (ret != EOK) {
+ continue;
+ }
+ }
+ }
+
+ ret = fputs(" </signal>\n", ictx->f);
+ if (ret < 0) return EIO;
+
+ return EOK;
+}
+
+static errno_t introspect_add_signals(struct introspect_ctx *ictx)
+{
+ errno_t ret;
+ int i;
+
+ if (ictx->iface->signals == NULL) {
+ /* An interface with no signals */
+ return EOK;
+ }
+
+ for (i = 0; ictx->iface->signals[i].name != NULL; i++) {
+ ret = introspect_add_sig(ictx, &ictx->iface->signals[i]);
+ if (ret != EOK) {
+ continue;
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t introspect_add_prop(struct introspect_ctx *ictx,
+ const struct sbus_property_meta *p)
+{
+ errno_t ret;
+
+ ret = fprintf(ictx->f, " <property name=\"%s\" type=\"%s\" access=\"%s\"/>\n",
+ p->name, p->type,
+ p->flags & SBUS_PROPERTY_WRITABLE ? "readwrite" : "read");
+ if (ret <= 0) return EIO;
+
+ return EOK;
+}
+
+static errno_t introspect_add_properties(struct introspect_ctx *ictx)
+{
+ errno_t ret;
+ int i;
+
+ if (ictx->iface->properties == NULL) {
+ /* An interface with no properties */
+ return EOK;
+ }
+
+ for (i = 0; ictx->iface->properties[i].name != NULL; i++) {
+ ret = introspect_add_prop(ictx, &ictx->iface->properties[i]);
+ if (ret != EOK) {
+ continue;
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t introspect_finish(struct introspect_ctx *ictx)
+{
+ errno_t ret;
+
+ ret = fputs(" </interface>\n", ictx->f);
+ if (ret < 0) return EIO;
+
+ ret = fputs(SSS_INTROSPECT_INTERFACE_INTROSPECTABLE, ictx->f);
+ if (ret < 0) return EIO;
+
+ ret = fputs("</node>\n", ictx->f);
+ if (ret < 0) return EIO;
+
+ fflush(ictx->f);
+ return EOK;
+}
+
+static char *sbus_introspect_xml(TALLOC_CTX *mem_ctx,
+ const struct sbus_interface_meta *iface)
+{
+ struct introspect_ctx *ictx;
+ char *buf_out = NULL;
+ errno_t ret;
+
+ ictx = talloc_zero(mem_ctx, struct introspect_ctx);
+ if (ictx == NULL) {
+ return NULL;
+ }
+ ictx->iface = iface;
+ talloc_set_destructor(ictx, introspect_ctx_destructor);
+
+ ret = introspect_begin(ictx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "introspect_begin failed: %d\n", ret);
+ goto done;
+ }
+
+ ret = introspect_add_methods(ictx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "introspect_add_methods failed: %d\n", ret);
+ goto done;
+ }
+
+ ret = introspect_add_signals(ictx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "introspect_add_signals failed: %d\n", ret);
+ goto done;
+ }
+
+ ret = introspect_add_properties(ictx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "introspect_add_properties failed: %d\n", ret);
+ goto done;
+ }
+
+ ret = introspect_finish(ictx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "introspect_finish failed: %d\n", ret);
+ goto done;
+ }
+
+ buf_out = talloc_memdup(mem_ctx, ictx->buf, ictx->size + 1);
+ DEBUG(SSSDBG_TRACE_LIBS, "Introspection: \n%s\n", buf_out);
+done:
+ talloc_free(ictx);
+ return buf_out;
+}
+
+int sbus_introspect(struct sbus_request *dbus_req, void *pvt)
+{
+ char *xml;
+ DBusError dberr;
+ const struct sbus_interface_meta *iface;
+ struct sbus_introspect_ctx *ictx;
+
+ ictx = talloc_get_type(pvt, struct sbus_introspect_ctx);
+ if (ictx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+ return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
+ }
+ iface = ictx->iface;
+
+ xml = sbus_introspect_xml(dbus_req, iface);
+ if (xml == NULL) {
+ dbus_error_init(&dberr);
+ dbus_set_error_const(&dberr,
+ DBUS_ERROR_NO_MEMORY,
+ "Failed to generate introspection data\n");
+ return sbus_request_fail_and_finish(dbus_req, &dberr);
+ }
+
+ return sbus_request_return_and_finish(dbus_req,
+ DBUS_TYPE_STRING, &xml,
+ DBUS_TYPE_INVALID);
+
+}
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index 88230cfca..929caeccb 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -98,4 +98,10 @@ struct sbus_request *
sbus_new_request(struct sbus_connection *conn, struct sbus_interface *intf,
DBusMessage *message);
+struct sbus_introspect_ctx {
+ const struct sbus_interface_meta *iface;
+};
+
+int sbus_introspect(struct sbus_request *dbus_req, void *pvt);
+
#endif /* _SSSD_DBUS_PRIVATE_H_ */