diff options
author | Bastien Nocera <hadess@hadess.net> | 2017-03-28 14:50:17 +0200 |
---|---|---|
committer | Bastien Nocera <hadess@hadess.net> | 2018-05-02 17:04:59 +0200 |
commit | a5afe7a0ee971371423edaca4fdd43b9b7b05a1e (patch) | |
tree | 958dbb100b80c28abf319c21350a504041a9dbc5 /src/gclue-client-info.c | |
parent | c26ecf714c4711ca92bec892b305c7de842ffade (diff) | |
download | geoclue-a5afe7a0ee971371423edaca4fdd43b9b7b05a1e.tar.gz |
client-info: Replace desktop ID detection for new Flatpak
For newer (>= 0.6.10) versions of Flatpak, the way to export the desktop
ID has changed from requiring cgroups to not requiring it.
See https://github.com/flatpak/flatpak/releases/tag/0.6.10
This changes the private gclue_client_info_get_xdg_id() API to return a
NULL xdg_id should the code fail to read the Flatpak ID for a Flatpak'ed
application, and consider it to be disqualifying:
"
Like parse_app_info_from_fileinfo(), returns NULL on failure,
"" (an empty string) if not sandboxed, and a desktop ID otherwise
"
https://bugs.freedesktop.org/show_bug.cgi?id=97776
Diffstat (limited to 'src/gclue-client-info.c')
-rw-r--r-- | src/gclue-client-info.c | 121 |
1 files changed, 80 insertions, 41 deletions
diff --git a/src/gclue-client-info.c b/src/gclue-client-info.c index 64057c0..5b1108e 100644 --- a/src/gclue-client-info.c +++ b/src/gclue-client-info.c @@ -21,6 +21,10 @@ */ #include <glib/gi18n.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> #include "gclue-client-info.h" @@ -181,52 +185,85 @@ on_name_vanished (GDBusConnection *connection, 0); } -/* Based on got_credentials_cb() from xdg-app source code */ -static char * -get_xdg_id (guint32 pid) +/* Based on xdp_get_app_id_from_pid() from xdg-desktop-portal + * Returns NULL on failure, keyfile with name "" if not sandboxed, and full app-info otherwise */ +static GKeyFile * +parse_app_info_from_fileinfo (int pid) { - char *xdg_id = NULL; - g_autofree char *path = NULL; - g_autofree char *content = NULL; - gchar **lines; - int i; - - path = g_strdup_printf ("/proc/%u/cgroup", pid); - - if (!g_file_get_contents (path, &content, NULL, NULL)) - return NULL; - lines = g_strsplit (content, "\n", -1); - - for (i = 0; lines[i] != NULL; i++) { - const char *unit = lines[i] + strlen ("1:name=systemd:"); - g_autofree char *scope = NULL; - const char *name; - char *dash; - - if (!g_str_has_prefix (lines[i], "1:name=systemd:")) - continue; - - scope = g_path_get_basename (unit); - if ((!g_str_has_prefix (scope, "xdg-app-") && - !g_str_has_prefix (scope, "flatpak-")) || - !g_str_has_suffix (scope, ".scope")) - break; - - /* strlen("flatpak-") == strlen("xdg-app-") - * so all is good here */ - name = scope + strlen("xdg-app-"); - dash = strchr (name, '-'); + g_autofree char *root_path = NULL; + g_autofree char *path = NULL; + g_autofree char *content = NULL; + g_autofree char *app_id = 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. */ + 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 */ + g_key_file_set_string (metadata, "Application", "name", ""); + return g_steal_pointer (&metadata); + } - if (dash == NULL) - break; + /* Some weird error => failure */ + return NULL; + } + + if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) + { + /* Some weird fd => failure */ + close (info_fd); + return NULL; + } + + mapped = g_mapped_file_new_from_fd (info_fd, FALSE, &local_error); + if (mapped == NULL) + { + close (info_fd); + 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); + return NULL; + } + + return g_steal_pointer (&metadata); +} - *dash = 0; - xdg_id = g_strdup (name); - } +static char * +get_xdg_id (guint32 pid) +{ + g_autoptr(GKeyFile) app_info = NULL; - g_strfreev (lines); + app_info = parse_app_info_from_fileinfo (pid); + if (app_info == NULL) + return NULL; - return xdg_id; + return g_key_file_get_string (app_info, "Application", "name", NULL); } static void @@ -437,6 +474,8 @@ gclue_client_info_check_bus_name (GClueClientInfo *info, return (strcmp (bus_name, info->priv->bus_name) == 0); } +/* Like parse_app_info_from_fileinfo(), returns NULL on failure, + * "" (an empty string) if not sandboxed, and a desktop ID otherwise */ const char * gclue_client_info_get_xdg_id (GClueClientInfo *info) { |