/* * Copyright © 2014 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: * Alexander Larsson * * Code borrowed from xdg-desktop-portal/src/xdp-utils.[ch] */ #include "config.h" #include #include #include #include #include #include #include "tracker-portal-utils.h" #define DBUS_NAME_DBUS "org.freedesktop.DBus" #define DBUS_INTERFACE_DBUS DBUS_NAME_DBUS #define DBUS_PATH_DBUS "/org/freedesktop/DBus" static GKeyFile * parse_app_info_from_flatpak_info (int pid, GError **error) { g_autofree char *root_path = NULL; int root_fd = -1; int info_fd = -1; struct stat stat_buf; g_autoptr(GError) local_error = NULL; g_autoptr(GMappedFile) mapped = NULL; g_autoptr(GKeyFile) metadata = NULL; root_path = g_strdup_printf ("/proc/%u/root", pid); root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); if (root_fd == -1) { /* Not able to open the root dir shouldn't happen. Probably the app died and * we're failing due to /proc/$pid not existing. In that case fail instead * of treating this as privileged. */ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unable to open %s", root_path); return NULL; } metadata = g_key_file_new (); info_fd = openat (root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY); close (root_fd); if (info_fd == -1) { if (errno == ENOENT) { /* No file => on the host, return NULL with no error */ return NULL; } /* Some weird error => failure */ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unable to open application info file"); return NULL; } if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) { /* Some weird fd => failure */ close (info_fd); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unable to open application info file"); return NULL; } mapped = g_mapped_file_new_from_fd (info_fd, FALSE, &local_error); if (mapped == NULL) { close (info_fd); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't map .flatpak-info file: %s", local_error->message); return NULL; } if (!g_key_file_load_from_data (metadata, g_mapped_file_get_contents (mapped), g_mapped_file_get_length (mapped), G_KEY_FILE_NONE, &local_error)) { close (info_fd); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't load .flatpak-info file: %s", local_error->message); return NULL; } close (info_fd); return g_steal_pointer (&metadata); } static GKeyFile * tracker_connection_lookup_app_info_sync (GDBusConnection *connection, const char *sender, GCancellable *cancellable, GError **error) { g_autoptr(GDBusMessage) msg = NULL; g_autoptr(GDBusMessage) reply = NULL; GVariant *body; g_autoptr(GVariantIter) iter = NULL; g_autoptr(GKeyFile) app_info = NULL; const char *key; GVariant *value; g_autoptr(GError) local_error = NULL; guint32 pid = 0; msg = g_dbus_message_new_method_call (DBUS_NAME_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionCredentials"); g_dbus_message_set_body (msg, g_variant_new ("(s)", sender)); reply = g_dbus_connection_send_message_with_reply_sync (connection, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 30000, NULL, cancellable, error); if (reply == NULL) return NULL; if (g_dbus_message_get_message_type (reply) == G_DBUS_MESSAGE_TYPE_ERROR) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find peer app id"); return NULL; } body = g_dbus_message_get_body (reply); g_variant_get (body, "(a{sv})", &iter); while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { if (strcmp (key, "ProcessID") == 0) pid = g_variant_get_uint32 (value); } if (pid == 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find app PID"); return NULL; } app_info = parse_app_info_from_flatpak_info (pid, &local_error); if (app_info == NULL && local_error) { g_propagate_error (error, g_steal_pointer (&local_error)); return NULL; } return g_steal_pointer (&app_info); } GKeyFile * tracker_invocation_lookup_app_info_sync (GDBusMethodInvocation *invocation, GCancellable *cancellable, GError **error) { GDBusConnection *connection = g_dbus_method_invocation_get_connection (invocation); const gchar *sender = g_dbus_method_invocation_get_sender (invocation); return tracker_connection_lookup_app_info_sync (connection, sender, cancellable, error); }