X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gdbus%2Fobject.c;h=900e7aba2968f1ee7d4a9013c793ef2543dde8ca;hb=335e7562aafe49d4f91184ebe4d84d1aa99b9ca7;hp=4375ec5e1c4cab55c19a15c2f00c2cdbb78b59ca;hpb=735cd2d81e0cc0696b868743030ac1fc4457e1e3;p=framework%2Fconnectivity%2Fconnman.git diff --git a/gdbus/object.c b/gdbus/object.c index 4375ec5..900e7ab 100644 --- a/gdbus/object.c +++ b/gdbus/object.c @@ -2,7 +2,7 @@ * * D-Bus helper library * - * Copyright (C) 2004-2008 Marcel Holtmann + * Copyright (C) 2004-2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify @@ -45,98 +45,84 @@ struct generic_data { struct interface_data { char *name; - GDBusMethodTable *methods; - GDBusSignalTable *signals; - GDBusPropertyTable *properties; + const GDBusMethodTable *methods; + const GDBusSignalTable *signals; + const GDBusPropertyTable *properties; void *user_data; GDBusDestroyFunction destroy; }; -static void print_arguments(GString *gstr, const char *sig, +struct security_data { + GDBusPendingReply pending; + DBusMessage *message; + const GDBusMethodTable *method; + void *iface_user_data; +}; + +static void print_arguments(GString *gstr, const GDBusArgInfo *args, const char *direction) { - int i; - - for (i = 0; sig[i]; i++) { - char type[32]; - int len, struct_level, dict_level; - gboolean complete; - - complete = FALSE; - struct_level = dict_level = 0; - memset(type, 0, sizeof(type)); - - /* Gather enough data to have a single complete type */ - for (len = 0; len < (sizeof(type) - 1) && sig[i]; len++, i++) { - switch (sig[i]){ - case '(': - struct_level++; - break; - case ')': - struct_level--; - if (struct_level <= 0 && dict_level <= 0) - complete = TRUE; - break; - case '{': - dict_level++; - break; - case '}': - dict_level--; - if (struct_level <= 0 && dict_level <= 0) - complete = TRUE; - break; - case 'a': - break; - default: - if (struct_level <= 0 && dict_level <= 0) - complete = TRUE; - break; - } - - type[len] = sig[i]; - - if (complete) - break; - } - + for (; args && args->name; args++) { + g_string_append_printf(gstr, + "\t\t\tname, args->signature); if (direction) g_string_append_printf(gstr, - "\t\t\t\n", - type, direction); + " direction=\"%s\"/>\n", direction); else - g_string_append_printf(gstr, - "\t\t\t\n", - type); + g_string_append_printf(gstr, "/>\n"); + } } static void generate_interface_xml(GString *gstr, struct interface_data *iface) { - GDBusMethodTable *method; - GDBusSignalTable *signal; + const GDBusMethodTable *method; + const GDBusSignalTable *signal; for (method = iface->methods; method && method->name; method++) { - if (!strlen(method->signature) && !strlen(method->reply)) + gboolean deprecated = method->flags & + G_DBUS_METHOD_FLAG_DEPRECATED; + gboolean noreply = method->flags & + G_DBUS_METHOD_FLAG_NOREPLY; + + if (!deprecated && !noreply && + !(method->in_args && method->in_args->name) && + !(method->out_args && method->out_args->name)) g_string_append_printf(gstr, "\t\t\n", method->name); else { g_string_append_printf(gstr, "\t\t\n", method->name); - print_arguments(gstr, method->signature, "in"); - print_arguments(gstr, method->reply, "out"); + print_arguments(gstr, method->in_args, "in"); + print_arguments(gstr, method->out_args, "out"); + + if (deprecated) + g_string_append_printf(gstr, "\t\t\t\n"); + + if (noreply) + g_string_append_printf(gstr, "\t\t\t\n"); + g_string_append_printf(gstr, "\t\t\n"); } } for (signal = iface->signals; signal && signal->name; signal++) { - if (!strlen(signal->signature)) + gboolean deprecated = signal->flags & + G_DBUS_SIGNAL_FLAG_DEPRECATED; + + if (!deprecated && !(signal->args && signal->args->name)) g_string_append_printf(gstr, "\t\t\n", signal->name); else { g_string_append_printf(gstr, "\t\t\n", signal->name); - print_arguments(gstr, signal->signature, NULL); + print_arguments(gstr, signal->args, NULL); + + if (deprecated) + g_string_append_printf(gstr, "\t\t\t\n"); + g_string_append_printf(gstr, "\t\t\n"); } } @@ -154,7 +140,7 @@ static void generate_introspection_xml(DBusConnection *conn, gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE); - g_string_append_printf(gstr, "\n", path); + g_string_append_printf(gstr, "\n"); for (list = data->interfaces; list; list = list->next) { struct interface_data *iface = list->data; @@ -182,34 +168,202 @@ done: data->introspect = g_string_free(gstr, FALSE); } -static DBusHandlerResult introspect(DBusConnection *connection, - DBusMessage *message, struct generic_data *data) +static DBusMessage *introspect(DBusConnection *connection, + DBusMessage *message, void *user_data) { + struct generic_data *data = user_data; DBusMessage *reply; - if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) { - error("Unexpected signature to introspect call"); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - if (!data->introspect) + if (data->introspect == NULL) generate_introspection_xml(connection, data, dbus_message_get_path(message)); reply = dbus_message_new_method_return(message); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + if (reply == NULL) + return NULL; dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect, DBUS_TYPE_INVALID); - dbus_connection_send(connection, reply, NULL); + 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; + + if (secdata->pending != pending) + continue; + + pending_security = g_slist_remove(pending_security, secdata); + + 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_valist(DBusConnection *connection, + GDBusPendingReply pending, const char *name, + const char *format, va_list args) +{ + GSList *list; + + for (list = pending_security; list; list = list->next) { + struct security_data *secdata = list->data; + DBusMessage *reply; + + if (secdata->pending != pending) + continue; + + pending_security = g_slist_remove(pending_security, secdata); + + reply = g_dbus_create_error_valist(secdata->message, + name, format, args); + if (reply != NULL) { + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + + dbus_message_unref(secdata->message); + g_free(secdata); + return; + } +} + +void g_dbus_pending_error(DBusConnection *connection, + GDBusPendingReply pending, + const char *name, const char *format, ...) +{ + va_list args; + + va_start(args, format); + + g_dbus_pending_error_valist(connection, pending, name, format, args); + + va_end(args); +} + +int polkit_check_authorization(DBusConnection *conn, + const char *action, gboolean interaction, + void (*function) (dbus_bool_t authorized, + void *user_data), + void *user_data, int timeout); + +struct builtin_security_data { + DBusConnection *conn; + GDBusPendingReply pending; +}; + +static void builtin_security_result(dbus_bool_t authorized, void *user_data) +{ + struct builtin_security_data *data = user_data; + + if (authorized == TRUE) + g_dbus_pending_success(data->conn, data->pending); + else + g_dbus_pending_error(data->conn, data->pending, + DBUS_ERROR_AUTH_FAILED, NULL); + + g_free(data); +} + +static void builtin_security_function(DBusConnection *conn, + const char *action, + gboolean interaction, + GDBusPendingReply pending) +{ + struct builtin_security_data *data; + + data = g_new0(struct builtin_security_data, 1); + data->conn = conn; + data->pending = pending; + + if (polkit_check_authorization(conn, action, interaction, + builtin_security_result, data, 30000) < 0) + g_dbus_pending_error(conn, pending, NULL, NULL); +} + +static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg, + const GDBusMethodTable *method, void *iface_user_data) +{ + const GDBusSecurityTable *security; + + for (security = security_table; security && security->privilege; + security++) { + struct security_data *secdata; + gboolean interaction; + + 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); + + if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION) + interaction = TRUE; + else + interaction = FALSE; + + if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) && + security->function) + security->function(conn, security->action, + interaction, secdata->pending); + else + builtin_security_function(conn, security->action, + interaction, secdata->pending); + + return TRUE; + } + + return FALSE; +} + static void generic_unregister(DBusConnection *connection, void *user_data) { struct generic_data *data = user_data; @@ -223,6 +377,9 @@ static struct interface_data *find_interface(GSList *interfaces, { GSList *list; + if (name == NULL) + return NULL; + for (list = interfaces; list; list = list->next) { struct interface_data *iface = list->data; if (!strcmp(name, iface->name)) @@ -232,57 +389,57 @@ static struct interface_data *find_interface(GSList *interfaces, return NULL; } +static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args, + DBusMessage *message) +{ + const char *sig = dbus_message_get_signature(message); + const char *p = NULL; + + for (; args && args->signature && *sig; args++) { + p = args->signature; + + for (; *sig && *p; sig++, p++) { + if (*p != *sig) + return FALSE; + } + } + + if (*sig || (p && *p) || (args && args->signature)) + return FALSE; + + return TRUE; +} + static DBusHandlerResult generic_message(DBusConnection *connection, DBusMessage *message, void *user_data) { struct generic_data *data = user_data; struct interface_data *iface; - GDBusMethodTable *method; + const GDBusMethodTable *method; const char *interface; - if (dbus_message_is_method_call(message, - DBUS_INTERFACE_INTROSPECTABLE, - "Introspect")) - return introspect(connection, message, data); - interface = dbus_message_get_interface(message); iface = find_interface(data->interfaces, interface); - if (!iface) + if (iface == NULL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 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; - if (dbus_message_has_signature(message, - method->signature) == FALSE) + if (g_dbus_args_have_signature(method->in_args, + message) == 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; @@ -300,18 +457,25 @@ static void invalidate_parent_data(DBusConnection *conn, const char *child_path) parent_path = g_strdup(child_path); slash = strrchr(parent_path, '/'); - if (!slash) + if (slash == NULL) goto done; - *slash = '\0'; + if (slash == parent_path && parent_path[1] != '\0') + parent_path[1] = '\0'; + else + *slash = '\0'; + if (!strlen(parent_path)) goto done; - if (!dbus_connection_get_object_path_data(conn, parent_path, - (void *) &data)) + if (dbus_connection_get_object_path_data(conn, parent_path, + (void *) &data) == FALSE) { goto done; + } + + invalidate_parent_data(conn, parent_path); - if (!data) + if (data == NULL) goto done; g_free(data->introspect); @@ -321,6 +485,32 @@ done: g_free(parent_path); } +static const GDBusMethodTable introspect_methods[] = { + { GDBUS_METHOD("Introspect", NULL, + GDBUS_ARGS({ "xml", "s" }), introspect) }, + { } +}; + +static void add_interface(struct generic_data *data, const char *name, + const GDBusMethodTable *methods, + const GDBusSignalTable *signals, + const GDBusPropertyTable *properties, + void *user_data, + GDBusDestroyFunction destroy) +{ + struct interface_data *iface; + + iface = g_new0(struct interface_data, 1); + iface->name = g_strdup(name); + iface->methods = methods; + iface->signals = signals; + iface->properties = properties; + iface->user_data = user_data; + iface->destroy = destroy; + + data->interfaces = g_slist_append(data->interfaces, iface); +} + static struct generic_data *object_path_ref(DBusConnection *connection, const char *path) { @@ -335,11 +525,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 ""); - data->refcount = 1; - if (!dbus_connection_register_object_path(connection, path, &generic_table, data)) { g_free(data->introspect); @@ -349,9 +538,31 @@ static struct generic_data *object_path_ref(DBusConnection *connection, invalidate_parent_data(connection, path); + add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, + introspect_methods, NULL, NULL, data, NULL); + return data; } +static gboolean remove_interface(struct generic_data *data, const char *name) +{ + struct interface_data *iface; + + iface = find_interface(data->interfaces, name); + if (iface == NULL) + return FALSE; + + data->interfaces = g_slist_remove(data->interfaces, iface); + + if (iface->destroy) + iface->destroy(iface->user_data); + + g_free(iface->name); + g_free(iface); + + return TRUE; +} + static void object_path_unref(DBusConnection *connection, const char *path) { struct generic_data *data = NULL; @@ -368,6 +579,8 @@ static void object_path_unref(DBusConnection *connection, const char *path) if (data->refcount > 0) return; + remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE); + invalidate_parent_data(connection, path); dbus_connection_unregister_object_path(connection, path); @@ -375,23 +588,22 @@ static void object_path_unref(DBusConnection *connection, const char *path) static gboolean check_signal(DBusConnection *conn, const char *path, const char *interface, const char *name, - const char **args) + const GDBusArgInfo **args) { struct generic_data *data = NULL; struct interface_data *iface; - GDBusSignalTable *signal; + const GDBusSignalTable *signal; *args = NULL; if (!dbus_connection_get_object_path_data(conn, path, - (void *) &data) || !data) { + (void *) &data) || data == NULL) { error("dbus_connection_emit_signal: path %s isn't registered", path); return FALSE; } iface = find_interface(data->interfaces, interface); - - if (!iface) { + if (iface == NULL) { error("dbus_connection_emit_signal: %s does not implement %s", path, interface); return FALSE; @@ -399,17 +611,13 @@ static gboolean check_signal(DBusConnection *conn, const char *path, for (signal = iface->signals; signal && signal->name; signal++) { if (!strcmp(signal->name, name)) { - *args = signal->signature; - break; + *args = signal->args; + return TRUE; } } - if (!*args) { - error("No signal named %s on interface %s", name, interface); - return FALSE; - } - - return TRUE; + error("No signal named %s on interface %s", name, interface); + return FALSE; } static dbus_bool_t emit_signal_valist(DBusConnection *conn, @@ -421,13 +629,13 @@ static dbus_bool_t emit_signal_valist(DBusConnection *conn, { DBusMessage *signal; dbus_bool_t ret; - const char *signature, *args; + const GDBusArgInfo *args; if (!check_signal(conn, path, interface, name, &args)) return FALSE; signal = dbus_message_new_signal(path, interface, name); - if (!signal) { + if (signal == NULL) { error("Unable to allocate new %s.%s signal", interface, name); return FALSE; } @@ -436,8 +644,7 @@ static dbus_bool_t emit_signal_valist(DBusConnection *conn, if (!ret) goto fail; - signature = dbus_message_get_signature(signal); - if (strcmp(args, signature) != 0) { + if (g_dbus_args_have_signature(args, signal) == FALSE) { error("%s.%s: expected signature'%s' but got '%s'", interface, name, args, signature); ret = FALSE; @@ -454,32 +661,25 @@ fail: gboolean g_dbus_register_interface(DBusConnection *connection, const char *path, const char *name, - GDBusMethodTable *methods, - GDBusSignalTable *signals, - GDBusPropertyTable *properties, + const GDBusMethodTable *methods, + const GDBusSignalTable *signals, + const GDBusPropertyTable *properties, void *user_data, GDBusDestroyFunction destroy) { struct generic_data *data; - struct interface_data *iface; data = object_path_ref(connection, path); if (data == NULL) return FALSE; - if (find_interface(data->interfaces, name)) + if (find_interface(data->interfaces, name)) { + object_path_unref(connection, path); return FALSE; + } - iface = g_new0(struct interface_data, 1); - - iface->name = g_strdup(name); - iface->methods = methods; - iface->signals = signals; - iface->properties = properties; - iface->user_data = user_data; - iface->destroy = destroy; - - data->interfaces = g_slist_append(data->interfaces, iface); + add_interface(data, name, methods, signals, + properties, user_data, destroy); g_free(data->introspect); data->introspect = NULL; @@ -491,7 +691,9 @@ gboolean g_dbus_unregister_interface(DBusConnection *connection, const char *path, const char *name) { struct generic_data *data = NULL; - struct interface_data *iface; + + if (path == NULL) + return FALSE; if (dbus_connection_get_object_path_data(connection, path, (void *) &data) == FALSE) @@ -500,18 +702,9 @@ gboolean g_dbus_unregister_interface(DBusConnection *connection, if (data == NULL) return FALSE; - iface = find_interface(data->interfaces, name); - if (!iface) + if (remove_interface(data, name) == FALSE) return FALSE; - data->interfaces = g_slist_remove(data->interfaces, iface); - - if (iface->destroy) - iface->destroy(iface->user_data); - - g_free(iface->name); - g_free(iface); - g_free(data->introspect); data->introspect = NULL; @@ -520,6 +713,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) {