+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 GDBusPendingPropertySet next_pending_property = 1;
+static GSList *pending_property_set;
+
+static struct property_data *remove_pending_property_data(
+ GDBusPendingPropertySet id)
+{
+ struct property_data *propdata;
+ GSList *l;
+
+ for (l = pending_property_set; l != NULL; l = l->next) {
+ propdata = l->data;
+ if (propdata->id != id)
+ continue;
+
+ break;
+ }
+
+ if (l == NULL)
+ return NULL;
+
+ pending_property_set = g_slist_delete_link(pending_property_set, l);
+
+ return propdata;
+}
+
+void g_dbus_pending_property_success(GDBusPendingPropertySet id)
+{
+ struct property_data *propdata;
+
+ propdata = remove_pending_property_data(id);
+ if (propdata == NULL)
+ return;
+
+ g_dbus_send_reply(propdata->conn, propdata->message,
+ DBUS_TYPE_INVALID);
+ dbus_message_unref(propdata->message);
+ g_free(propdata);
+}
+
+void g_dbus_pending_property_error_valist(GDBusPendingReply id,
+ const char *name, const char *format,
+ va_list args)
+{
+ struct property_data *propdata;
+
+ propdata = remove_pending_property_data(id);
+ if (propdata == NULL)
+ return;
+
+ g_dbus_send_error_valist(propdata->conn, propdata->message, name,
+ format, args);
+
+ dbus_message_unref(propdata->message);
+ g_free(propdata);
+}
+
+void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
+ const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+
+ g_dbus_pending_property_error_valist(id, name, format, args);
+
+ va_end(args);
+}
+
+static void reset_parent(gpointer data, gpointer user_data)
+{
+ struct generic_data *child = data;
+ struct generic_data *parent = user_data;
+
+ child->parent = parent;
+}
+
+static void append_property(struct interface_data *iface,
+ const GDBusPropertyTable *p, DBusMessageIter *dict)
+{
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &p->name);
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, p->type,
+ &value);
+
+ p->get(p, &value, iface->user_data);
+
+ dbus_message_iter_close_container(&entry, &value);
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_properties(struct interface_data *data,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter dict;
+ const GDBusPropertyTable *p;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ for (p = data->properties; p && p->name; p++) {
+ if (check_experimental(p->flags,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+ continue;
+
+ if (p->get == NULL)
+ continue;
+
+ if (p->exists != NULL && !p->exists(p, data->user_data))
+ continue;
+
+ append_property(data, p, &dict);
+ }
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+static void append_interface(gpointer data, gpointer user_data)
+{
+ struct interface_data *iface = data;
+ DBusMessageIter *array = user_data;
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
+ append_properties(data, &entry);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+static void emit_interfaces_added(struct generic_data *data)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter, array;
+
+ if (root == NULL || data == root)
+ return;
+
+ signal = dbus_message_new_signal(root->path,
+ DBUS_INTERFACE_OBJECT_MANAGER,
+ "InterfacesAdded");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &data->path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ g_slist_foreach(data->added, append_interface, &array);
+ g_slist_free(data->added);
+ data->added = NULL;
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
+ dbus_connection_send(data->conn, signal, NULL);
+ dbus_message_unref(signal);
+}
+