diff options
author | Brian Cameron <Brian.Cameron@sun.com> | 2009-09-11 20:27:27 -0500 |
---|---|---|
committer | Brian Cameron <Brian.Cameron@sun.com> | 2009-09-11 20:27:27 -0500 |
commit | c25ef9245be4e0be2126ef3d075df4401949b570 (patch) | |
tree | 222a15fd151feb7e8c82c87a91a01e6e751a8771 /daemon | |
parent | 54282f9068272b05e0d3bd78fb23400474437eaa (diff) | |
download | gdm-c25ef9245be4e0be2126ef3d075df4401949b570.tar.gz |
Store the face and dmrc files in a cache. Refer to bug #565151.
Diffstat (limited to 'daemon')
-rw-r--r-- | daemon/Makefile.am | 1 | ||||
-rw-r--r-- | daemon/gdm-session-settings.c | 7 | ||||
-rw-r--r-- | daemon/gdm-session-settings.h | 2 | ||||
-rw-r--r-- | daemon/gdm-session-worker.c | 265 |
4 files changed, 239 insertions, 36 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 3daf9245..a122a158 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -15,6 +15,7 @@ AM_CPPFLAGS = \ -DSBINDIR=\"$(sbindir)\" \ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ -DGDM_XAUTH_DIR=\"$(GDM_XAUTH_DIR)\" \ + -DGDM_CACHE_DIR=\""$(localstatedir)/cache/gdm"\" \ -DGDM_SESSION_DEFAULT_PATH=\"$(GDM_SESSION_DEFAULT_PATH)\" \ $(DISABLE_DEPRECATED_CFLAGS) \ $(DAEMON_CFLAGS) \ diff --git a/daemon/gdm-session-settings.c b/daemon/gdm-session-settings.c index b6c04f7c..421d87ad 100644 --- a/daemon/gdm-session-settings.c +++ b/daemon/gdm-session-settings.c @@ -267,7 +267,7 @@ gdm_session_settings_is_loaded (GdmSessionSettings *settings) gboolean gdm_session_settings_load (GdmSessionSettings *settings, - const char *home_directory, + const char *username, GError **error) { GKeyFile *key_file; @@ -279,9 +279,10 @@ gdm_session_settings_load (GdmSessionSettings *settings, char *filename; g_return_val_if_fail (settings != NULL, FALSE); - g_return_val_if_fail (home_directory != NULL, FALSE); + g_return_val_if_fail (username != NULL, FALSE); g_return_val_if_fail (!gdm_session_settings_is_loaded (settings), FALSE); - filename = g_build_filename (home_directory, ".dmrc", NULL); + + filename = g_build_filename (GDM_CACHE_DIR, username, "dmrc", NULL); is_loaded = FALSE; key_file = g_key_file_new (); diff --git a/daemon/gdm-session-settings.h b/daemon/gdm-session-settings.h index a5465984..d579d4ad 100644 --- a/daemon/gdm-session-settings.h +++ b/daemon/gdm-session-settings.h @@ -54,7 +54,7 @@ GType gdm_session_settings_get_type (void); GdmSessionSettings *gdm_session_settings_new (void); gboolean gdm_session_settings_load (GdmSessionSettings *settings, - const char *home_directory, + const char *username, GError **error); gboolean gdm_session_settings_save (GdmSessionSettings *settings, const char *home_directory, diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c index 13e08b1e..7a1fafb4 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -42,6 +42,7 @@ #include <glib/gi18n.h> #include <glib/gstdio.h> #include <glib-object.h> +#include <gio/gio.h> #define DBUS_API_SUBJECT_TO_CHANGE #include <dbus/dbus.h> #include <dbus/dbus-glib.h> @@ -88,6 +89,8 @@ #define MESSAGE_REPLY_TIMEOUT (10 * 60 * 1000) +#define MAX_FILE_SIZE 65536 + enum { GDM_SESSION_WORKER_STATE_NONE = 0, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE, @@ -121,6 +124,7 @@ struct GdmSessionWorkerPrivate char *hostname; char *username; uid_t uid; + gid_t gid; gboolean password_is_required; int cred_flags; @@ -590,39 +594,9 @@ static void attempt_to_load_user_settings (GdmSessionWorker *worker, const char *username) { - struct passwd *passwd_entry; - uid_t old_uid; - gid_t old_gid; - - old_uid = geteuid (); - old_gid = getegid (); - - passwd_entry = getpwnam (username); - - /* User input isn't a valid username - */ - if (passwd_entry == NULL) { - return; - } - - /* We may get called late in the pam conversation after - * the user has already been authenticated. This could - * happen if for instance, the user's home directory isn't - * available until late in the pam conversation so user - * settings couldn't get loaded until late in the conversation. - * If we get called late the seteuid/setgid calls here will fail, - * but that's okay, because we'll already be the uid/gid we want - * to be. - */ - setegid (passwd_entry->pw_gid); - seteuid (passwd_entry->pw_uid); - gdm_session_settings_load (worker->priv->user_settings, - passwd_entry->pw_dir, + username, NULL); - - seteuid (old_uid); - setegid (old_gid); } static void @@ -969,6 +943,219 @@ gdm_session_worker_stop_auditor (GdmSessionWorker *worker) worker->priv->auditor = NULL; } +static gboolean +check_user_copy_file (const char *srcfile, + const char *destfile, + uid_t user, + gssize max_file_size) +{ + struct stat srcfileinfo; + struct stat destfileinfo; + + if (max_file_size < 0) { + max_file_size = G_MAXSIZE; + } + + /* Exists/Readable? */ + if (g_stat (srcfile, &srcfileinfo) < 0) { + g_debug ("File does not exist"); + return FALSE; + } + + /* Is newer than the file already in the cache? */ + if (destfile != NULL && g_stat (destfile, &destfileinfo) == 0) { + if (srcfileinfo.st_mtime <= destfileinfo.st_mtime) { + g_debug ("Destination file is newer"); + return FALSE; + } + } + + /* Is a regular file */ + if (G_UNLIKELY (!S_ISREG (srcfileinfo.st_mode))) { + g_debug ("File is not a regular file"); + return FALSE; + } + + /* Owned by user? */ + if (G_UNLIKELY (srcfileinfo.st_uid != user)) { + g_debug ("File is not owned by user"); + return FALSE; + } + + /* Size is kosher? */ + if (G_UNLIKELY (srcfileinfo.st_size > max_file_size)) { + g_debug ("File is too large"); + return FALSE; + } + + return TRUE; +} + +static gboolean +gdm_cache_copy_file (GdmSessionWorker *worker, + const char *userfilename, + const char *cachefilename) +{ + gboolean res; + + g_debug ("Checking if %s should be copied to cache %s", + userfilename, cachefilename); + + res = check_user_copy_file (userfilename, + cachefilename, + worker->priv->uid, + MAX_FILE_SIZE); + + if (res) { + GFile *src_file; + GFile *dst_file; + GError *error; + + src_file = g_file_new_for_path (userfilename); + dst_file = g_file_new_for_path (cachefilename); + + error = NULL; + res = g_file_copy (src_file, + dst_file, + G_FILE_COPY_OVERWRITE | + G_FILE_COPY_NOFOLLOW_SYMLINKS, + NULL, + NULL, + NULL, + &error); + + if (! res) { + g_warning ("Could not copy file to cache: %s", + error->message); + g_error_free (error); + } else { + chown (cachefilename, + worker->priv->uid, + worker->priv->gid); + g_chmod (cachefilename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + g_debug ("Copy successful"); + } + + g_object_unref (src_file); + g_object_unref (dst_file); + } else { + g_debug ("Not copying file %s to cache", + userfilename); + } + return res; +} + +static char * +gdm_session_worker_create_cachedir (GdmSessionWorker *worker) +{ + struct stat statbuf; + char *cachedir; + int r; + + cachedir = g_build_filename (GDM_CACHE_DIR, + worker->priv->username, + NULL); + + /* Verify user cache directory exists, create if needed */ + r = g_stat (cachedir, &statbuf); + if (r < 0) { + g_debug ("Making user cache directory %s", cachedir); + g_mkdir (cachedir, + S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH); + g_chmod (cachedir, + S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH); + } + chown (cachedir, worker->priv->uid, worker->priv->gid); + + return cachedir; +} + +static void +gdm_session_worker_cache_userfiles (GdmSessionWorker *worker) +{ + struct passwd *passwd_entry; + char *cachedir; + char *cachefile; + char *userfile; + gboolean res; + + passwd_entry = getpwnam (worker->priv->username); + if (passwd_entry == NULL) + return; + + cachedir = gdm_session_worker_create_cachedir (worker); + + g_debug ("Copying user dmrc file to cache"); + cachefile = g_build_filename (cachedir, "dmrc", NULL); + userfile = g_build_filename (passwd_entry->pw_dir, ".dmrc", NULL); + + gdm_cache_copy_file (worker, userfile, cachefile); + g_free (cachefile); + g_free (userfile); + + g_debug ("Copying user face file to cache"); + cachefile = g_build_filename (cachedir, + "face", + NULL); + + /* First, try "~/.face" */ + userfile = g_build_filename (passwd_entry->pw_dir, ".face", NULL); + res = gdm_cache_copy_file (worker, userfile, cachefile); + + /* Next, try "~/.face.icon" */ + if (!res) { + g_free (userfile); + userfile = g_build_filename (passwd_entry->pw_dir, + ".face.icon", + NULL); + res = gdm_cache_copy_file (worker, + userfile, + cachefile); + } + + /* Still nothing, try the user's personal GDM config */ + if (!res) { + char *tempfilename; + + tempfilename = g_build_filename (passwd_entry->pw_dir, + ".gnome", + "gdm", + NULL); + + g_debug ("Checking user's ~/.gnome/gdm file"); + res = check_user_copy_file (tempfilename, + NULL, + worker->priv->uid, + MAX_FILE_SIZE); + if (res) { + GKeyFile *keyfile; + + g_free (userfile); + + keyfile = g_key_file_new (); + g_key_file_load_from_file (keyfile, + userfile, + G_KEY_FILE_NONE, + NULL); + + userfile = g_key_file_get_string (keyfile, + "face", + "picture", + NULL); + res = gdm_cache_copy_file (worker, + userfile, + cachefile); + + g_key_file_free (keyfile); + } + g_free (tempfilename); + } + + g_free (cachedir); + g_free (cachefile); + g_free (userfile); +} + static void gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker, int status) @@ -979,6 +1166,7 @@ gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker, return; if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) { + gdm_session_worker_cache_userfiles (worker); pam_close_session (worker->priv->pam_handle, 0); gdm_session_auditor_report_logout (worker->priv->auditor); @@ -1345,6 +1533,7 @@ _change_user (GdmSessionWorker *worker, } #endif worker->priv->uid = uid; + worker->priv->gid = gid; if (setgid (gid) < 0) { return FALSE; @@ -1733,7 +1922,11 @@ _save_user_settings (GdmSessionWorker *worker, GError *error; if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) { - return; + /* + * Even if the user did not change the defaults, there may + * be files to cache + */ + goto out; } error = NULL; @@ -1743,6 +1936,9 @@ _save_user_settings (GdmSessionWorker *worker, error->message); g_error_free (error); } + +out: + gdm_session_worker_cache_userfiles (worker); } static gboolean @@ -1796,9 +1992,14 @@ gdm_session_worker_start_user_session (GdmSessionWorker *worker, if (session_pid == 0) { char **environment; + char *cachedirname; char *home_dir; int fd; + /* Make sure cachedir gets created before we drop to user */ + cachedirname = gdm_session_worker_create_cachedir (worker); + g_free (cachedirname); + if (setuid (worker->priv->uid) < 0) { g_debug ("GdmSessionWorker: could not reset uid - %s", g_strerror (errno)); _exit (1); |