diff options
author | William Jon McCann <mccann@jhu.edu> | 2007-09-19 19:09:55 +0000 |
---|---|---|
committer | William Jon McCann <mccann@src.gnome.org> | 2007-09-19 19:09:55 +0000 |
commit | 35bfabd70c866b6325d4b98f8fd1c3b486b5b747 (patch) | |
tree | 02b1c2ac0a6965179f08f7c5b5a6099ddcc59226 /daemon | |
parent | 02cdcd6ed67a820f795629ef8a80ab21b75800c1 (diff) | |
download | gdm-35bfabd70c866b6325d4b98f8fd1c3b486b5b747.tar.gz |
Manage the lifecycle of the D-Bus session since the X server doesn't exit.
2007-09-19 William Jon McCann <mccann@jhu.edu>
* daemon/gdm-greeter-session.c: (get_greeter_environment),
(signal_pid), (spawn_child_setup),
(spawn_command_line_sync_as_user),
(spawn_command_line_async_as_user), (parse_value_as_integer),
(parse_dbus_launch_output), (start_dbus_daemon),
(stop_dbus_daemon), (gdm_greeter_session_spawn),
(gdm_greeter_session_stop), (gdm_greeter_session_init),
(gdm_greeter_session_finalize):
* gui/simple-greeter/gdm-language-chooser-widget.c:
(parse_short_name):
Manage the lifecycle of the D-Bus session since
the X server doesn't exit.
svn path=/branches/mccann-gobject/; revision=5295
Diffstat (limited to 'daemon')
-rw-r--r-- | daemon/gdm-greeter-session.c | 470 |
1 files changed, 353 insertions, 117 deletions
diff --git a/daemon/gdm-greeter-session.c b/daemon/gdm-greeter-session.c index 01df95c1..3446d427 100644 --- a/daemon/gdm-greeter-session.c +++ b/daemon/gdm-greeter-session.c @@ -44,6 +44,8 @@ #include "gdm-greeter-session.h" +#define DBUS_LAUNCH_COMMAND "dbus-launch --exit-with-session" + #define GDM_GREETER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/GreeterServer" #define GDM_GREETER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.GreeterServer" @@ -75,6 +77,9 @@ struct GdmGreeterSessionPrivate guint child_watch_id; + GPid dbus_pid; + char *dbus_bus_address; + char *server_address; }; @@ -104,74 +109,6 @@ static void gdm_greeter_session_finalize (GObject *object); G_DEFINE_TYPE (GdmGreeterSession, gdm_greeter_session, G_TYPE_OBJECT) - -static void -change_user (GdmGreeterSession *greeter_session) - -{ - struct passwd *pwent; - struct group *grent; - - if (greeter_session->priv->user_name == NULL) { - return; - } - - pwent = getpwnam (greeter_session->priv->user_name); - if (pwent == NULL) { - g_warning (_("GreeterSession was to be spawned by user %s but that user doesn't exist"), - greeter_session->priv->user_name); - _exit (1); - } - - grent = getgrnam (greeter_session->priv->group_name); - if (grent == NULL) { - g_warning (_("GreeterSession was to be spawned by group %s but that user doesn't exist"), - greeter_session->priv->group_name); - _exit (1); - } - - g_debug ("Changing (uid:gid) for child process to (%d:%d)", - pwent->pw_uid, - grent->gr_gid); - - if (pwent->pw_uid != 0) { - if (setgid (grent->gr_gid) < 0) { - g_warning (_("Couldn't set groupid to %d"), - grent->gr_gid); - _exit (1); - } - - if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) { - g_warning (_("initgroups () failed for %s"), - pwent->pw_name); - _exit (1); - } - - if (setuid (pwent->pw_uid) < 0) { - g_warning (_("Couldn't set userid to %d"), - (int)pwent->pw_uid); - _exit (1); - } - } else { - gid_t groups[1] = { 0 }; - - if (setgid (0) < 0) { - g_warning (_("Couldn't set groupid to 0")); - /* Don't error out, it's not fatal, if it fails we'll - * just still be */ - } - - /* this will get rid of any suplementary groups etc... */ - setgroups (1, groups); - } -} - -static void -greeter_session_child_setup (GdmGreeterSession *greeter_session) -{ - change_user (greeter_session); -} - static void listify_hash (const char *key, const char *value, @@ -301,6 +238,7 @@ get_greeter_environment (GdmGreeterSession *greeter_session) /* create a hash table of current environment, then update keys has necessary */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert (hash, g_strdup ("DBUS_SESSION_BUS_ADDRESS"), g_strdup (greeter_session->priv->dbus_bus_address)); g_hash_table_insert (hash, g_strdup ("GDM_GREETER_DBUS_ADDRESS"), g_strdup (greeter_session->priv->server_address)); g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (greeter_session->priv->x11_authority_file)); @@ -442,43 +380,355 @@ greeter_session_child_watch (GPid pid, } } +static int +signal_pid (int pid, + int signal) +{ + int status = -1; + + /* perhaps block sigchld */ + + status = kill (pid, signal); + + if (status < 0) { + if (errno == ESRCH) { + g_warning ("Child process %lu was already dead.", + (unsigned long) pid); + } else { + g_warning ("Couldn't kill child process %lu: %s", + (unsigned long) pid, + g_strerror (errno)); + } + } + + /* perhaps unblock sigchld */ + + return status; +} + +typedef struct { + const char *user_name; + const char *group_name; +} SpawnChildData; + +static void +spawn_child_setup (SpawnChildData *data) +{ + struct passwd *pwent; + struct group *grent; + + if (data->user_name == NULL) { + return; + } + + pwent = getpwnam (data->user_name); + if (pwent == NULL) { + g_warning (_("User %s doesn't exist"), + data->user_name); + _exit (1); + } + + grent = getgrnam (data->group_name); + if (grent == NULL) { + g_warning (_("Group %s doesn't exist"), + data->group_name); + _exit (1); + } + + g_debug ("Changing (uid:gid) for child process to (%d:%d)", + pwent->pw_uid, + grent->gr_gid); + + if (pwent->pw_uid != 0) { + if (setgid (grent->gr_gid) < 0) { + g_warning (_("Couldn't set groupid to %d"), + grent->gr_gid); + _exit (1); + } + + if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) { + g_warning (_("initgroups () failed for %s"), + pwent->pw_name); + _exit (1); + } + + if (setuid (pwent->pw_uid) < 0) { + g_warning (_("Couldn't set userid to %d"), + (int)pwent->pw_uid); + _exit (1); + } + } else { + gid_t groups[1] = { 0 }; + + if (setgid (0) < 0) { + g_warning (_("Couldn't set groupid to 0")); + /* Don't error out, it's not fatal, if it fails we'll + * just still be */ + } + + /* this will get rid of any suplementary groups etc... */ + setgroups (1, groups); + } +} + static gboolean -gdm_greeter_session_spawn (GdmGreeterSession *greeter_session) +spawn_command_line_sync_as_user (const char *command_line, + const char *user_name, + const char *group_name, + char **env, + char **std_output, + char **std_error, + int *exit_status, + GError **error) { - gchar **argv; - GError *error; - GPtrArray *env; + char **argv; + GError *local_error; gboolean ret; + gboolean res; + SpawnChildData data; ret = FALSE; - create_temp_auth_file (greeter_session); + argv = NULL; + local_error = NULL; + if (! g_shell_parse_argv (command_line, NULL, &argv, &local_error)) { + g_warning ("Could not parse command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } - g_debug ("Running greeter_session process: %s", greeter_session->priv->command); + data.user_name = user_name; + data.group_name = group_name; + + local_error = NULL; + res = g_spawn_sync (NULL, + argv, + env, + G_SPAWN_SEARCH_PATH, + (GSpawnChildSetupFunc)spawn_child_setup, + &data, + std_output, + std_error, + exit_status, + &local_error); + + if (! res) { + g_warning ("Could not spawn command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } + + ret = TRUE; + out: + g_strfreev (argv); + + return ret; +} + +static gboolean +spawn_command_line_async_as_user (const char *command_line, + const char *user_name, + const char *group_name, + char **env, + GPid *child_pid, + GError **error) +{ + char **argv; + GError *local_error; + gboolean ret; + gboolean res; + SpawnChildData data; + + ret = FALSE; argv = NULL; - if (! g_shell_parse_argv (greeter_session->priv->command, NULL, &argv, &error)) { - g_warning ("Could not parse command: %s", error->message); + local_error = NULL; + if (! g_shell_parse_argv (command_line, NULL, &argv, &local_error)) { + g_warning ("Could not parse command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } + + data.user_name = user_name; + data.group_name = group_name; + + local_error = NULL; + res = g_spawn_async (NULL, + argv, + env, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, + (GSpawnChildSetupFunc)spawn_child_setup, + &data, + child_pid, + &local_error); + if (! res) { + g_warning ("Could not spawn command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } + + ret = TRUE; + out: + g_strfreev (argv); + + return ret; +} + +static gboolean +parse_value_as_integer (const char *value, + int *intval) +{ + char *end_of_valid_int; + glong long_value; + gint int_value; + + errno = 0; + long_value = strtol (value, &end_of_valid_int, 10); + + if (*value == '\0' || *end_of_valid_int != '\0') { + return FALSE; + } + + int_value = long_value; + if (int_value != long_value || errno == ERANGE) { + return FALSE; + } + + *intval = int_value; + + return TRUE; +} + +static gboolean +parse_dbus_launch_output (const char *output, + char **addressp, + GPid *pidp) +{ + GRegex *re; + GMatchInfo *match_info; + gboolean ret; + gboolean res; + GError *error; + + ret = FALSE; + + error = NULL; + re = g_regex_new ("DBUS_SESSION_BUS_ADDRESS=(.+)\nDBUS_SESSION_BUS_PID=([0-9]+)", 0, 0, &error); + if (re == NULL) { + g_critical (error->message); + } + + g_regex_match (re, output, 0, &match_info); + + res = g_match_info_matches (match_info); + if (! res) { + g_warning ("Unable to parse output: %s", output); + goto out; + } + + if (addressp != NULL) { + *addressp = g_strdup (g_match_info_fetch (match_info, 1)); + } + + if (pidp != NULL) { + int pid; + gboolean res; + res = parse_value_as_integer (g_match_info_fetch (match_info, 2), &pid); + if (res) { + *pidp = pid; + } else { + *pidp = 0; + } + } + + ret = TRUE; + + out: + g_match_info_free (match_info); + g_regex_unref (re); + + return ret; +} + +static gboolean +start_dbus_daemon (GdmGreeterSession *greeter_session) +{ + gboolean res; + char *std_out; + char *std_err; + int exit_status; + GError *error; + + error = NULL; + res = spawn_command_line_sync_as_user (DBUS_LAUNCH_COMMAND, + greeter_session->priv->user_name, + greeter_session->priv->group_name, + NULL, + &std_out, + &std_err, + &exit_status, + &error); + if (! res) { + g_warning ("Unable to launch D-Bus daemon: %s", error->message); g_error_free (error); goto out; } + /* pull the address and pid from the output */ + res = parse_dbus_launch_output (std_out, + &greeter_session->priv->dbus_bus_address, + &greeter_session->priv->dbus_pid); + if (! res) { + g_warning ("Unable to parse D-Bus launch output"); + } else { + g_debug ("Started D-Bus daemon on pid %d", greeter_session->priv->dbus_pid); + } + out: + return res; +} + +static gboolean +stop_dbus_daemon (GdmGreeterSession *greeter_session) +{ + if (greeter_session->priv->dbus_pid > 0) { + signal_pid (greeter_session->priv->dbus_pid, SIGTERM); + greeter_session->priv->dbus_pid = 0; + } + return TRUE; +} + +static gboolean +gdm_greeter_session_spawn (GdmGreeterSession *greeter_session) +{ + char **argv; + GError *error; + GPtrArray *env; + gboolean ret; + gboolean res; + + ret = FALSE; + + res = start_dbus_daemon (greeter_session); + if (! res) { + /* FIXME: */ + } + + create_temp_auth_file (greeter_session); + + g_debug ("Running greeter_session process: %s", greeter_session->priv->command); + open_greeter_session (greeter_session); env = get_greeter_environment (greeter_session); error = NULL; - ret = g_spawn_async_with_pipes (NULL, - argv, - (char **)env->pdata, - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, - (GSpawnChildSetupFunc)greeter_session_child_setup, - greeter_session, - &greeter_session->priv->pid, - NULL, - NULL, - NULL, - &error); + + ret = spawn_command_line_async_as_user (greeter_session->priv->command, + greeter_session->priv->user_name, + greeter_session->priv->group_name, + (char **)env->pdata, + &greeter_session->priv->pid, + &error); g_ptr_array_foreach (env, (GFunc)g_free, NULL); g_ptr_array_free (env, TRUE); @@ -488,15 +738,15 @@ gdm_greeter_session_spawn (GdmGreeterSession *greeter_session) greeter_session->priv->command, error->message); g_error_free (error); + goto out; } else { g_debug ("gdm_slave_greeter_session: GreeterSession on pid %d", (int)greeter_session->priv->pid); } greeter_session->priv->child_watch_id = g_child_watch_add (greeter_session->priv->pid, - (GChildWatchFunc)greeter_session_child_watch, - greeter_session); + (GChildWatchFunc)greeter_session_child_watch, + greeter_session); - g_strfreev (argv); out: return ret; @@ -526,32 +776,6 @@ gdm_greeter_session_start (GdmGreeterSession *greeter_session) } static int -signal_pid (int pid, - int signal) -{ - int status = -1; - - /* perhaps block sigchld */ - - status = kill (pid, signal); - - if (status < 0) { - if (errno == ESRCH) { - g_warning ("Child process %lu was already dead.", - (unsigned long) pid); - } else { - g_warning ("Couldn't kill child process %lu: %s", - (unsigned long) pid, - g_strerror (errno)); - } - } - - /* perhaps unblock sigchld */ - - return status; -} - -static int wait_on_child (int pid) { int status; @@ -613,6 +837,8 @@ gdm_greeter_session_stop (GdmGreeterSession *greeter_session) close_greeter_session (greeter_session); } + stop_dbus_daemon (greeter_session); + return TRUE; } @@ -878,7 +1104,7 @@ gdm_greeter_session_init (GdmGreeterSession *greeter_session) greeter_session->priv->pid = -1; - greeter_session->priv->command = g_strdup ("dbus-launch --exit-with-session " LIBEXECDIR "/gdm-simple-greeter"); + greeter_session->priv->command = g_strdup (LIBEXECDIR "/gdm-simple-greeter"); greeter_session->priv->user_max_filesize = 65536; } @@ -896,6 +1122,16 @@ gdm_greeter_session_finalize (GObject *object) gdm_greeter_session_stop (greeter_session); + g_free (greeter_session->priv->command); + g_free (greeter_session->priv->user_name); + g_free (greeter_session->priv->group_name); + g_free (greeter_session->priv->x11_display_name); + g_free (greeter_session->priv->x11_display_device); + g_free (greeter_session->priv->x11_display_hostname); + g_free (greeter_session->priv->x11_authority_file); + g_free (greeter_session->priv->dbus_bus_address); + g_free (greeter_session->priv->server_address); + if (greeter_session->priv->ckc != NULL) { ck_connector_unref (greeter_session->priv->ckc); } |