Add support for GDBus security handlers

This commit is contained in:
Marcel Holtmann 2010-08-29 00:18:47 +02:00
parent 3bf4209813
commit 8ef8135a2a
2 changed files with 156 additions and 22 deletions

View File

@ -55,6 +55,11 @@ typedef void (* GDBusDestroyFunction) (void *user_data);
typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
DBusMessage *message, void *user_data);
typedef guint32 GDBusPendingReply;
typedef void (* GDBusSecurityFunction) (DBusConnection *connection,
DBusMessage *message, GDBusPendingReply pending);
typedef enum {
G_DBUS_METHOD_FLAG_DEPRECATED = (1 << 0),
G_DBUS_METHOD_FLAG_NOREPLY = (1 << 1),
@ -75,6 +80,7 @@ typedef struct {
const char *reply;
GDBusMethodFunction function;
GDBusMethodFlags flags;
unsigned int privilege;
} GDBusMethodTable;
typedef struct {
@ -89,6 +95,11 @@ typedef struct {
GDBusPropertyFlags flags;
} GDBusPropertyTable;
typedef struct {
unsigned int privilege;
GDBusSecurityFunction function;
} GDBusSecurityTable;
gboolean g_dbus_register_interface(DBusConnection *connection,
const char *path, const char *name,
const GDBusMethodTable *methods,
@ -99,6 +110,14 @@ gboolean g_dbus_register_interface(DBusConnection *connection,
gboolean g_dbus_unregister_interface(DBusConnection *connection,
const char *path, const char *name);
gboolean g_dbus_register_security(const GDBusSecurityTable *security);
gboolean g_dbus_unregister_security(const GDBusSecurityTable *security);
void g_dbus_pending_success(DBusConnection *connection,
GDBusPendingReply pending);
void g_dbus_pending_error(DBusConnection *connection,
GDBusPendingReply pending, DBusMessage *error);
DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
const char *format, ...)
__attribute__((format(printf, 3, 4)));

View File

@ -52,6 +52,13 @@ struct interface_data {
GDBusDestroyFunction destroy;
};
struct security_data {
GDBusPendingReply pending;
DBusMessage *message;
const GDBusMethodTable *method;
void *iface_user_data;
};
static void print_arguments(GString *gstr, const char *sig,
const char *direction)
{
@ -208,6 +215,114 @@ static DBusMessage *introspect(DBusConnection *connection,
return reply;
}
static DBusHandlerResult process_message(DBusConnection *connection,
DBusMessage *message, const GDBusMethodTable *method,
void *iface_user_data)
{
DBusMessage *reply;
reply = method->function(connection, message, iface_user_data);
if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
if (reply != NULL)
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
if (reply == NULL)
return DBUS_HANDLER_RESULT_HANDLED;
}
if (reply == NULL)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_connection_send(connection, reply, NULL);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static GDBusPendingReply next_pending = 1;
static GSList *pending_security = NULL;
static const GDBusSecurityTable *security_table = NULL;
void g_dbus_pending_success(DBusConnection *connection,
GDBusPendingReply pending)
{
GSList *list;
for (list = pending_security; list; list = list->next) {
struct security_data *secdata = list->data;
DBusHandlerResult result;
if (secdata->pending != pending)
continue;
pending_security = g_slist_remove(pending_security, secdata);
result = process_message(connection, secdata->message,
secdata->method, secdata->iface_user_data);
dbus_message_unref(secdata->message);
g_free(secdata);
return;
}
}
void g_dbus_pending_error(DBusConnection *connection,
GDBusPendingReply pending, DBusMessage *error)
{
GSList *list;
for (list = pending_security; list; list = list->next) {
struct security_data *secdata = list->data;
if (secdata->pending != pending)
continue;
pending_security = g_slist_remove(pending_security, secdata);
if (error != NULL) {
dbus_connection_send(connection, error, NULL);
dbus_message_unref(error);
}
dbus_message_unref(secdata->message);
g_free(secdata);
return;
}
}
static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
const GDBusMethodTable *method, void *iface_user_data)
{
const GDBusSecurityTable *security;
for (security = security_table; security && security->function &&
security->privilege; security++) {
struct security_data *secdata;
if (security->privilege != method->privilege)
continue;
secdata = g_new(struct security_data, 1);
secdata->pending = next_pending++;
secdata->message = dbus_message_ref(msg);
secdata->method = method;
secdata->iface_user_data = iface_user_data;
pending_security = g_slist_prepend(pending_security, secdata);
security->function(conn, secdata->message, secdata->pending);
return TRUE;
}
return FALSE;
}
static void generic_unregister(DBusConnection *connection, void *user_data)
{
struct generic_data *data = user_data;
@ -249,8 +364,6 @@ static DBusHandlerResult generic_message(DBusConnection *connection,
for (method = iface->methods; method &&
method->name && method->function; method++) {
DBusMessage *reply;
if (dbus_message_is_method_call(message, iface->name,
method->name) == FALSE)
continue;
@ -259,26 +372,12 @@ static DBusHandlerResult generic_message(DBusConnection *connection,
method->signature) == FALSE)
continue;
reply = method->function(connection, message, iface->user_data);
if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
if (reply != NULL)
dbus_message_unref(reply);
if (check_privilege(connection, message, method,
iface->user_data) == TRUE)
return DBUS_HANDLER_RESULT_HANDLED;
}
if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
if (reply == NULL)
return DBUS_HANDLER_RESULT_HANDLED;
}
if (reply == NULL)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_connection_send(connection, reply, NULL);
dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
return process_message(connection, message, method,
iface->user_data);
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@ -362,11 +461,10 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
}
data = g_new0(struct generic_data, 1);
data->refcount = 1;
data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
data->refcount = 1;
if (!dbus_connection_register_object_path(connection, path,
&generic_table, data)) {
g_free(data->introspect);
@ -556,6 +654,23 @@ gboolean g_dbus_unregister_interface(DBusConnection *connection,
return TRUE;
}
gboolean g_dbus_register_security(const GDBusSecurityTable *security)
{
if (security_table != NULL)
return FALSE;
security_table = security;
return TRUE;
}
gboolean g_dbus_unregister_security(const GDBusSecurityTable *security)
{
security_table = NULL;
return TRUE;
}
DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
const char *format, va_list args)
{