diff -up mate-desktop/libmate-desktop/mate-desktop-thumbnail.c~ mate-desktop/libmate-desktop/mate-desktop-thumbnail.c --- mate-desktop/libmate-desktop/mate-desktop-thumbnail.c~ 2022-09-27 15:30:19.801968422 +0200 +++ mate-desktop/libmate-desktop/mate-desktop-thumbnail.c 2022-09-27 15:30:19.823968573 +0200 @@ -32,8 +32,11 @@ #include #include +#include + #define MATE_DESKTOP_USE_UNSTABLE_API #include "mate-desktop-thumbnail.h" +#include "mate-desktop-utils.h" static void thumbnailers_directory_changed (GFileMonitor *monitor, @@ -55,6 +58,11 @@ struct _MateDesktopThumbnailFactoryPriva gboolean loaded : 1; gboolean disabled : 1; gchar **disabled_types; + + gboolean permissions_problem; + gboolean needs_chown; + uid_t real_uid; + gid_t real_gid; }; static const char *appname = "mate-thumbnail-factory"; @@ -544,6 +552,49 @@ external_thumbnailers_disabled_changed_c g_mutex_unlock (&priv->lock); } +/* There are various different behavior depending on whether the application + ran with sudo, pkexec, under the root user, and 'sudo su'... + + - sudo (program) keeps the user's home folder (and their .cache folder) + - pkexec (program) uses root's .cache folder + - root terminal, running (program) uses root's .cache folder + - sudo su, then running (program), uses root's .cache folder + + Using sudo, or sudo su, SUDO_UID and friends are set in the environment + Using pkexec, PKEXEC_UID is set + + root terminal and pkexec cases don't need any extra work - they're thumbnailing + with the correct permissions (root-owned in root's .cache folder) + + sudo and sudo su need help, and each in a different way: + - sudo su gives a false positive, since SUDO_UID is set, *but* the program + is using root's .cache folder, so we really don't want to fix these + - sudo (program) wants to use the user's cache folder, but will end up writing + them as root:root files, instead of user:user. So, in this case, we make sure + to chmod those files to be owned by the original user, and not root. +*/ + +static void +get_user_info (MateDesktopThumbnailFactory *factory, + gboolean *adjust, + uid_t *uid, + gid_t *gid) +{ + struct passwd *pwent; + + pwent = mate_desktop_get_session_user_pwent (); + + *uid = pwent->pw_uid; + *gid = pwent->pw_gid; + + /* Only can (and need to) adjust if we're root, but + this process will be writing to the session user's + home folder */ + + *adjust = geteuid () == 0 && + g_strcmp0 (pwent->pw_dir, g_get_home_dir ()) == 0; +} + static void mate_desktop_thumbnail_factory_init (MateDesktopThumbnailFactory *factory) { @@ -560,6 +611,10 @@ mate_desktop_thumbnail_factory_init (Mat (GDestroyNotify)g_free, (GDestroyNotify)thumbnailer_unref); + get_user_info (factory, &priv->needs_chown, &priv->real_uid, &priv->real_gid); + + priv->permissions_problem = !mate_desktop_thumbnail_cache_check_permissions (NULL, TRUE); + g_mutex_init (&priv->lock); priv->settings = g_settings_new ("org.mate.thumbnailers"); @@ -833,6 +888,9 @@ mate_desktop_thumbnail_factory_can_thumb { gboolean have_script = FALSE; + if (factory->priv->permissions_problem) + return FALSE; + /* Don't thumbnail thumbnails */ if (uri && strncmp (uri, "file:/", 6) == 0 && @@ -1350,3 +1408,202 @@ mate_desktop_thumbnail_is_valid (GdkPixb return TRUE; } + +static void +fix_owner (const gchar *path, uid_t uid, gid_t gid) +{ + G_GNUC_UNUSED int res; + + res = chown (path, uid, gid); +} + +static gboolean +access_ok (const gchar *path, uid_t uid, gid_t gid) +{ + /* user mode will always trip on this */ + if (g_access (path, R_OK|W_OK) != 0) { + if (errno != ENOENT && errno != EFAULT) + return FALSE; + else + return TRUE; + } + + /* root will need to check against the real user */ + + GStatBuf buf; + + gint ret = g_stat (path, &buf); + + if (ret == 0) { + if (buf.st_uid != uid || buf.st_gid != gid || (buf.st_mode & (S_IRUSR|S_IWUSR)) == 0) + return FALSE; + } + + return TRUE; +} + +static void +recursively_fix_file (const gchar *path, uid_t uid, gid_t gid) +{ + if (!access_ok (path, uid, gid)) + fix_owner (path, uid, gid); + + if (g_file_test (path, G_FILE_TEST_IS_DIR)) { + GDir *dir = g_dir_open (path, 0, NULL); + + if (dir) { + const char *name; + + while ((name = g_dir_read_name (dir))) { + gchar *filename; + + filename = g_build_filename (path, name, NULL); + recursively_fix_file (filename, uid, gid); + g_free (filename); + } + + g_dir_close (dir); + } + } +} + +static gboolean +recursively_check_file (const gchar *path, uid_t uid, gid_t gid) +{ + if (!access_ok (path, uid, gid)) + return FALSE; + + gboolean ret = TRUE; + + if (g_file_test (path, G_FILE_TEST_IS_DIR)) { + GDir *dir = g_dir_open (path, 0, NULL); + + if (dir) { + const char *name; + + while ((name = g_dir_read_name (dir))) { + gchar *filename; + filename = g_build_filename (path, name, NULL); + + if (!recursively_check_file (filename, uid, gid)) { + ret = FALSE; + } + + g_free (filename); + + if (!ret) + break; + } + + g_dir_close (dir); + } + } + + return ret; +} + +static gboolean +check_subfolder_permissions_only (const gchar *path, uid_t uid, gid_t gid) +{ + gboolean ret = TRUE; + + GDir *dir = g_dir_open (path, 0, NULL); + + if (dir) { + const char *name; + + while ((name = g_dir_read_name (dir))) { + gchar *filename; + filename = g_build_filename (path, name, NULL); + + if (!access_ok (filename, uid, gid)) { + ret = FALSE; + } + + g_free (filename); + + if (!ret) + break; + } + + g_dir_close (dir); + } + + return ret; +} + +/** + * mate_desktop_cache_fix_permissions: + * + * Fixes any file or folder ownership issues for the *currently + * logged-in* user. Note - this may not be the same as the uid + * of the user running this operation. + * + **/ + +void +mate_desktop_thumbnail_cache_fix_permissions (void) +{ + struct passwd *pwent; + + pwent = mate_desktop_get_session_user_pwent (); + + gchar *cache_dir = g_build_filename (pwent->pw_dir, ".cache", "thumbnails", NULL); + + if (!access_ok (cache_dir, pwent->pw_uid, pwent->pw_gid)) + fix_owner (cache_dir, pwent->pw_uid, pwent->pw_gid); + + recursively_fix_file (cache_dir, pwent->pw_uid, pwent->pw_gid); + + g_free (cache_dir); +} + +/** + * mate_desktop_cache_check_permissions: + * @factory: (allow-none): an optional MateDesktopThumbnailFactory + * @quick: if TRUE, only do a quick check of directory ownersip + * This is more serious than thumbnail ownership issues, and is faster. + * + * Returns whether there are any ownership issues with the thumbnail + * folders and existing thumbnails for the *currently logged-in* user. + * Note - this may not be the same as the uid of the user running this + * check. + * + * if factory is not NULL, factory->priv->permissions_problem will be + * set to the result of the check. + * + * Return value: TRUE if everything checks out in these folders for the + * logged in user. + * + **/ + +gboolean +mate_desktop_thumbnail_cache_check_permissions (MateDesktopThumbnailFactory *factory, gboolean quick) +{ + gboolean checks_out = TRUE; + + struct passwd *pwent; + pwent = mate_desktop_get_session_user_pwent (); + + gchar *cache_dir = g_build_filename (pwent->pw_dir, ".cache", "thumbnails", NULL); + + if (!access_ok (cache_dir, pwent->pw_uid, pwent->pw_gid)) { + checks_out = FALSE; + goto out; + } + + if (quick) { + checks_out = check_subfolder_permissions_only (cache_dir, pwent->pw_uid, pwent->pw_gid); + } else { + checks_out = recursively_check_file (cache_dir, pwent->pw_uid, pwent->pw_gid); + } + +out: + g_free (cache_dir); + + if (factory) + factory->priv->permissions_problem = !checks_out; + + return checks_out; +} + diff -up mate-desktop/libmate-desktop/mate-desktop-thumbnail.h~ mate-desktop/libmate-desktop/mate-desktop-thumbnail.h --- mate-desktop/libmate-desktop/mate-desktop-thumbnail.h~ 2022-09-27 15:30:22.037983795 +0200 +++ mate-desktop/libmate-desktop/mate-desktop-thumbnail.h 2022-09-27 15:30:22.038983802 +0200 @@ -96,6 +96,10 @@ gboolean mate_desktop_thumbnail_is_val char * mate_desktop_thumbnail_path_for_uri (const char *uri, MateDesktopThumbnailSize size); +/* Thumbnail folder checking and fixing utils */ +void mate_desktop_thumbnail_cache_fix_permissions (void); +gboolean mate_desktop_thumbnail_cache_check_permissions (MateDesktopThumbnailFactory *factory, gboolean quick); + G_END_DECLS #endif /* MATE_DESKTOP_THUMBNAIL_H */ diff -up mate-desktop/libmate-desktop/mate-desktop-utils.c~ mate-desktop/libmate-desktop/mate-desktop-utils.c --- mate-desktop/libmate-desktop/mate-desktop-utils.c~ 2022-09-27 15:30:24.804002812 +0200 +++ mate-desktop/libmate-desktop/mate-desktop-utils.c 2022-09-27 15:30:24.815002887 +0200 @@ -459,3 +459,41 @@ mate_desktop_gtk_style_get_dark_color (G gtk_style_context_get_background_color (style, state, color); gtk_style_shade (color, color, DARKNESS_MULT); } + +/** + * mate_desktop_get_session_user_pwent: (skip) + * + * Description: Makes a best effort to retrieve the currently + * logged-in user's passwd struct (containing uid, gid, home, etc...) + * based on the process uid and various environment variables. + * + * Returns: (transfer none): the passwd struct corresponding to the + * session user (or, as a last resort, the user returned by getuid()) + **/ + +struct passwd * +mate_desktop_get_session_user_pwent (void) +{ + struct passwd *pwent = NULL; + + if (getuid () != geteuid ()) { + gint uid = getuid (); + pwent = getpwuid (uid); + } else if (g_getenv ("SUDO_UID") != NULL) { + gint uid = (int) g_ascii_strtoll (g_getenv ("SUDO_UID"), NULL, 10); + pwent = getpwuid (uid); + } else if (g_getenv ("PKEXEC_UID") != NULL) { + gint uid = (int) g_ascii_strtoll (g_getenv ("PKEXEC_UID"), NULL, 10); + pwent = getpwuid (uid); + } else if (g_getenv ("USERNAME") != NULL) { + pwent = getpwnam (g_getenv ("USERNAME")); + } else if (g_getenv ("USER") != NULL) { + pwent = getpwnam (g_getenv ("USER")); + } + + if (!pwent) { + return getpwuid (getuid ()); + } + + return pwent; +} diff -up mate-desktop/libmate-desktop/mate-desktop-utils.h~ mate-desktop/libmate-desktop/mate-desktop-utils.h --- mate-desktop/libmate-desktop/mate-desktop-utils.h~ 2022-09-27 15:30:27.261019704 +0200 +++ mate-desktop/libmate-desktop/mate-desktop-utils.h 2022-09-27 15:30:27.262019711 +0200 @@ -34,6 +34,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -53,6 +54,8 @@ mate_desktop_gtk_style_get_dark_color (G GtkStateFlags state, GdkRGBA *color); +struct passwd *mate_desktop_get_session_user_pwent (void); + G_END_DECLS #endif /* MATE_DESKTOP_UTILS_H */ [luti@c8-v1 Desktop]$