diff options
author | Robert Ancell <robert.ancell@canonical.com> | 2012-03-01 14:29:29 +1100 |
---|---|---|
committer | Robert Ancell <robert.ancell@canonical.com> | 2012-03-01 14:29:29 +1100 |
commit | a5c9f9f4c0a163dd487b5918f2742b08ab990dfb (patch) | |
tree | 7f302f236a9e0b0fcc7305b28462d93c2872bea7 /src/session.c | |
parent | e86b408cd06e9a8ca9d4baf1e7ad73537637f450 (diff) | |
download | lightdm-a5c9f9f4c0a163dd487b5918f2742b08ab990dfb.tar.gz |
Restructure session code so the PAM authentication is run in its own process.
Diffstat (limited to 'src/session.c')
-rw-r--r-- | src/session.c | 789 |
1 files changed, 466 insertions, 323 deletions
diff --git a/src/session.c b/src/session.c index a4bfd2b7..cb300d65 100644 --- a/src/session.c +++ b/src/session.c @@ -17,478 +17,600 @@ #include <fcntl.h> #include <glib/gstdio.h> #include <grp.h> +#include <pwd.h> #include "session.h" +#include "configuration.h" #include "console-kit.h" +enum { + GOT_MESSAGES, + AUTHENTICATION_COMPLETE, + STOPPED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + struct SessionPrivate { - /* File to log to */ - gchar *log_file; + /* PID of child process */ + GPid pid; + + /* Pipes to talk to child */ + int to_child_input; + int from_child_output; + GIOChannel *from_child_channel; + guint from_child_watch; + guint child_watch; + + /* User to authenticate as */ + gchar *username; + + /* User object that matches the current username */ + User *user; - /* TRUE if the log file should be owned by the user */ - gboolean log_file_as_user; + /* Messages being requested by PAM */ + int messages_length; + struct pam_message *messages; - /* Authentication for this session */ - PAMSession *authentication; + /* Authentication result from PAM */ + gboolean authentication_started; + gboolean authentication_complete; + int authentication_result; + gchar *authentication_result_string; + + /* File to log to */ + gchar *log_filename; + + /* Seat class */ + gchar *class; - /* Command to run for this session */ - gchar *command; + /* tty this session is running on */ + gchar *tty; + + /* X display connected to */ + gchar *xdisplay; + XAuthority *xauthority; + gboolean xauth_use_system_location; - /* ConsoleKit parameters for this session */ - GHashTable *console_kit_parameters; + /* Remote host this session is being controlled from */ + gchar *remote_host_name; - /* ConsoleKit cookie for the session */ + /* Console kit cookie */ gchar *console_kit_cookie; - /* TRUE if this is a greeter session */ - gboolean is_greeter; + /* Environment to set in child */ + GList *env; }; -G_DEFINE_TYPE (Session, session, PROCESS_TYPE); +/* Maximum length of a string to pass between daemon and session */ +#define MAX_STRING_LENGTH 65535 + +G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT); void -session_set_log_file (Session *session, const gchar *filename, gboolean as_user) +session_set_log_file (Session *session, const gchar *filename) { g_return_if_fail (session != NULL); - g_free (session->priv->log_file); - session->priv->log_file = g_strdup (filename); - session->priv->log_file_as_user = as_user; -} - -const gchar * -session_get_log_file (Session *session) -{ - g_return_val_if_fail (session != NULL, NULL); - return session->priv->log_file; + g_free (session->priv->log_filename); + session->priv->log_filename = g_strdup (filename); } void -session_set_authentication (Session *session, PAMSession *authentication) +session_set_class (Session *session, const gchar *class) { g_return_if_fail (session != NULL); - session->priv->authentication = g_object_ref (authentication); + g_free (session->priv->class); + session->priv->class = g_strdup (class); } -PAMSession * -session_get_authentication (Session *session) +void +session_set_tty (Session *session, const gchar *tty) { - g_return_val_if_fail (session != NULL, NULL); - return session->priv->authentication; + g_return_if_fail (session != NULL); + g_free (session->priv->tty); + session->priv->tty = g_strdup (tty); } -User * -session_get_user (Session *session) +void +session_set_xdisplay (Session *session, const gchar *xdisplay) { - g_return_val_if_fail (session != NULL, NULL); - return pam_session_get_user (session->priv->authentication); + g_return_if_fail (session != NULL); + g_free (session->priv->xdisplay); + session->priv->xdisplay = g_strdup (xdisplay); } void -session_set_is_greeter (Session *session, gboolean is_greeter) +session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location) { g_return_if_fail (session != NULL); - session->priv->is_greeter = is_greeter; + if (session->priv->xauthority) + g_object_unref (session->priv->xauthority); + session->priv->xauthority = g_object_ref (authority); + session->priv->xauth_use_system_location = use_system_location; } -gboolean -session_get_is_greeter (Session *session) +void +session_set_remote_host_name (Session *session, const gchar *remote_host_name) { - g_return_val_if_fail (session != NULL, FALSE); - return session->priv->is_greeter; + g_return_if_fail (session != NULL); + g_free (session->priv->remote_host_name); + session->priv->remote_host_name = g_strdup (remote_host_name); } void -session_set_command (Session *session, const gchar *command) +session_set_env (Session *session, const gchar *name, const gchar *value) { g_return_if_fail (session != NULL); - - g_free (session->priv->command); - session->priv->command = g_strdup (command); + session->priv->env = g_list_append (session->priv->env, g_strdup_printf ("%s=%s", name, value)); } -const gchar * -session_get_command (Session *session) +User * +session_get_user (Session *session) { g_return_val_if_fail (session != NULL, NULL); - return session->priv->command; -} - -static gchar * -get_absolute_command (const gchar *command) -{ - gchar **tokens; - gchar *absolute_binary, *absolute_command = NULL; - - tokens = g_strsplit (command, " ", 2); - absolute_binary = g_find_program_in_path (tokens[0]); - if (absolute_binary) - { - if (tokens[1]) - absolute_command = g_strjoin (" ", absolute_binary, tokens[1], NULL); - else - absolute_command = g_strdup (absolute_binary); - } - g_free (absolute_binary); + if (session->priv->username == NULL) + return NULL; - g_strfreev (tokens); + if (!session->priv->user) + session->priv->user = accounts_get_user_by_name (session->priv->username); - return absolute_command; + return session->priv->user; } static void -set_env_from_authentication (Session *session, PAMSession *authentication) +write_data (Session *session, const void *buf, size_t count) { - gchar **pam_env; - - pam_env = pam_session_get_envlist (authentication); - if (pam_env) - { - gchar *env_string; - int i; - - env_string = g_strjoinv (" ", pam_env); - g_debug ("PAM returns environment '%s'", env_string); - g_free (env_string); - - for (i = 0; pam_env[i]; i++) - { - gchar **pam_env_vars = g_strsplit (pam_env[i], "=", 2); - if (pam_env_vars && pam_env_vars[0] && pam_env_vars[1]) - session_set_env (session, pam_env_vars[0], pam_env_vars[1]); - else - g_warning ("Can't parse PAM environment variable %s", pam_env[i]); - g_strfreev (pam_env_vars); - } - g_strfreev (pam_env); - } + if (write (session->priv->to_child_input, buf, count) != count) + g_warning ("Error writing to session: %s", strerror (errno)); } -void -session_set_env (Session *session, const gchar *name, const gchar *value) +static void +write_string (Session *session, const char *value) { - g_return_if_fail (session != NULL); - g_return_if_fail (name != NULL); - process_set_env (PROCESS (session), name, value); + int length; + + length = value ? strlen (value) : -1; + write_data (session, &length, sizeof (length)); + if (value) + write_data (session, value, sizeof (char) * length); } -const gchar * -session_get_env (Session *session, const gchar *name) +static ssize_t +read_from_child (Session *session, void *buf, size_t count) { - g_return_val_if_fail (session != NULL, NULL); - g_return_val_if_fail (name != NULL, NULL); - return process_get_env (PROCESS (session), name); + ssize_t n_read; + n_read = read (session->priv->from_child_output, buf, count); + if (n_read < 0) + g_warning ("Error reading from session: %s", strerror (errno)); + return n_read; } -void -session_set_console_kit_parameter (Session *session, const gchar *name, GVariant *value) +static gchar * +read_string_from_child (Session *session) { - g_return_if_fail (session != NULL); - g_return_if_fail (name != NULL); + int length; + char *value; + + if (read_from_child (session, &length, sizeof (length)) <= 0) + return NULL; + if (length < 0) + return NULL; + if (length > MAX_STRING_LENGTH) + { + g_warning ("Invalid string length %d from child", length); + return NULL; + } + + value = g_malloc (sizeof (char) * (length + 1)); + read_from_child (session, value, length); + value[length] = '\0'; - g_hash_table_insert (session->priv->console_kit_parameters, - g_strdup (name), g_variant_ref_sink (value)); + return value; } -const gchar * -session_get_console_kit_cookie (Session *session) +static void +session_watch_cb (GPid pid, gint status, gpointer data) { - g_return_val_if_fail (session != NULL, NULL); - return session->priv->console_kit_cookie; + Session *session = data; + + session->priv->pid = 0; + + if (WIFEXITED (status)) + g_debug ("Session %d exited with return value %d", pid, WEXITSTATUS (status)); + else if (WIFSIGNALED (status)) + g_debug ("Session %d terminated with signal %d", pid, WTERMSIG (status)); + + /* If failed during authentication then report this as an authentication failure */ + if (session->priv->authentication_started && !session->priv->authentication_complete) + { + g_debug ("Session %d failed during authentication", pid); + session->priv->authentication_complete = TRUE; + session->priv->authentication_result = PAM_CONV_ERR; + g_free (session->priv->authentication_result_string); + session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion"); + g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0); + } + + g_signal_emit (G_OBJECT (session), signals[STOPPED], 0); } -/* Set the LANG variable based on the chosen locale. This is not a great - * solution, as it will override the locale set in PAM (which is where it - * should be set). In the case of Ubuntu these will be overridden by setting - * these variables in ~/.profile */ -static void -set_locale (Session *session) +static gboolean +from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data) { - User *user; - const gchar *locale; + Session *session = data; + gchar *username; + ssize_t n_read; + gboolean auth_complete; - user = pam_session_get_user (session->priv->authentication); - locale = user_get_locale (user); - if (locale) + /* Remote end gone */ + if (condition == G_IO_HUP) { - g_debug ("Using locale %s", locale); - session_set_env (session, "LANG", locale); + session->priv->from_child_watch = 0; + return FALSE; } -} -/* Insert our own utility directory to PATH - * This is to provide gdmflexiserver which provides backwards compatibility - * with GDM. - * Must be done after set_env_from_authentication because PAM sets PATH. - * This can be removed when this is no longer required. - */ -static void -insert_utility_path (Session *session) -{ - const gchar *orig_path; + /* Get the username currently being authenticated (may change during authentication) */ + username = read_string_from_child (session); + if (g_strcmp0 (username, session->priv->username) != 0) + { + g_free (session->priv->username); + session->priv->username = username; + if (session->priv->user) + g_object_unref (session->priv->user); + session->priv->user = NULL; + } + else + g_free (username); - orig_path = session_get_env (session, "PATH"); - if (orig_path) + /* Check if authentication completed */ + n_read = read_from_child (session, &auth_complete, sizeof (auth_complete)); + if (n_read < 0) + g_debug ("Error reading from child: %s", strerror (errno)); + if (n_read <= 0) { - gchar *path = g_strdup_printf ("%s:%s", PKGLIBEXEC_DIR, orig_path); - session_set_env (session, "PATH", path); - g_free (path); + session->priv->from_child_watch = 0; + return FALSE; } -} -gboolean -session_start (Session *session) -{ - User *user; + if (auth_complete) + { + session->priv->authentication_complete = TRUE; + read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result)); + g_free (session->priv->authentication_result_string); + session->priv->authentication_result_string = read_string_from_child (session); - g_return_val_if_fail (session != NULL, FALSE); - g_return_val_if_fail (session->priv->authentication != NULL, FALSE); - g_return_val_if_fail (session->priv->command != NULL, FALSE); + g_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string); - g_debug ("Launching session"); + /* No longer expect any more messages */ + session->priv->from_child_watch = 0; - user = pam_session_get_user (session->priv->authentication); - - /* Set POSIX variables */ - session_set_env (session, "PATH", "/usr/local/bin:/usr/bin:/bin"); - session_set_env (session, "USER", user_get_name (user)); - session_set_env (session, "LOGNAME", user_get_name (user)); - session_set_env (session, "HOME", user_get_home_directory (user)); - session_set_env (session, "SHELL", user_get_shell (user)); + g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0); + + return FALSE; + } + else + { + int i; + + session->priv->messages_length = 0; + read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length)); + session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message)); + for (i = 0; i < session->priv->messages_length; i++) + { + struct pam_message *m = &session->priv->messages[i]; + read_from_child (session, &m->msg_style, sizeof (m->msg_style)); + m->msg = read_string_from_child (session); + } - return SESSION_GET_CLASS (session)->start (session); + g_debug ("Session %d got %d message(s) from PAM", session->priv->pid, session->priv->messages_length); + + g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0); + } + + return TRUE; } -static gboolean -session_real_start (Session *session) +gboolean +session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive) { - gboolean result; - gchar *absolute_command; + int version; + int to_child_pipe[2], from_child_pipe[2]; + int to_child_output, from_child_input; + + g_return_val_if_fail (session != NULL, FALSE); + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (session->priv->pid == 0, FALSE); - absolute_command = get_absolute_command (session->priv->command); - if (!absolute_command) + /* Create pipes to talk to the child */ + if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0) { - g_debug ("Can't launch session %s, not found in path", session->priv->command); + g_warning ("Failed to create pipe to communicated with session process: %s", strerror (errno)); return FALSE; } - process_set_command (PROCESS (session), absolute_command); - g_free (absolute_command); - - pam_session_open (session->priv->authentication); - - /* Open ConsoleKit session */ - if (getuid () == 0) + to_child_output = to_child_pipe[0]; + session->priv->to_child_input = to_child_pipe[1]; + session->priv->from_child_output = from_child_pipe[0]; + from_child_input = from_child_pipe[1]; + session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output); + session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session); + + /* Don't allow the daemon end of the pipes to be accessed in child processes */ + fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC); + fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC); + + /* Remember what username we started with - it will be updated by PAM during authentication */ + session->priv->username = g_strdup (username); + + /* Run the child */ + session->priv->pid = fork (); + if (session->priv->pid < 0) { - GVariantBuilder parameters; - User *user; - GHashTableIter iter; - gpointer key, value; - - user = pam_session_get_user (session->priv->authentication); - - g_variant_builder_init (¶meters, G_VARIANT_TYPE ("(a(sv))")); - g_variant_builder_open (¶meters, G_VARIANT_TYPE ("a(sv)")); - g_variant_builder_add (¶meters, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user))); - if (session->priv->is_greeter) - g_variant_builder_add (¶meters, "(sv)", "session-type", g_variant_new_string ("LoginWindow")); - g_hash_table_iter_init (&iter, session->priv->console_kit_parameters); - while (g_hash_table_iter_next (&iter, &key, &value)) - g_variant_builder_add (¶meters, "(sv)", (gchar *) key, (GVariant *) value); - - g_free (session->priv->console_kit_cookie); - session->priv->console_kit_cookie = ck_open_session (¶meters); + g_debug ("Failed to fork session child process: %s", strerror (errno)); + return FALSE; } - else + if (session->priv->pid == 0) { - g_free (session->priv->console_kit_cookie); - session->priv->console_kit_cookie = g_strdup (g_getenv ("XDG_SESSION_COOKIE")); + /* Run us again in session child mode */ + execlp ("lightdm", + "lightdm", + "--session-child", + g_strdup_printf ("%d", to_child_output), + g_strdup_printf ("%d", from_child_input), + NULL); + _exit (EXIT_FAILURE); } - if (session->priv->console_kit_cookie) - session_set_env (session, "XDG_SESSION_COOKIE", session->priv->console_kit_cookie); + /* Listen for session termination */ + session->priv->authentication_started = TRUE; + session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session); - if (!SESSION_GET_CLASS (session)->setup (session)) - return FALSE; - - result = process_start (PROCESS (session)); + /* Close the ends of the pipes we don't need */ + close (to_child_output); + close (from_child_input); - if (!result) + /* Indicate what version of the protocol we are using */ + version = 0; + write_data (session, &version, sizeof (version)); + + /* Send configuration */ + write_string (session, service); + write_string (session, username); + write_data (session, &do_authenticate, sizeof (do_authenticate)); + write_data (session, &is_interactive, sizeof (is_interactive)); + write_string (session, session->priv->class); + write_string (session, session->priv->tty); + write_string (session, session->priv->remote_host_name); + write_string (session, session->priv->xdisplay); + if (session->priv->xauthority) { - pam_session_close (session->priv->authentication); - if (getuid () == 0 && session->priv->console_kit_cookie) - ck_close_session (session->priv->console_kit_cookie); - } + guint16 family; + gsize length; + + write_string (session, xauth_get_authorization_name (session->priv->xauthority)); + family = xauth_get_family (session->priv->xauthority); + write_data (session, &family, sizeof (family)); + length = xauth_get_address_length (session->priv->xauthority); + write_data (session, &length, sizeof (length)); + write_data (session, xauth_get_address (session->priv->xauthority), length); + write_string (session, xauth_get_number (session->priv->xauthority)); + length = xauth_get_authorization_data_length (session->priv->xauthority); + write_data (session, &length, sizeof (length)); + write_data (session, xauth_get_authorization_data (session->priv->xauthority), length); + } + else + write_string (session, NULL); - return result; + g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, service, username); + + return TRUE; } -void -session_lock (Session *session) -{ - g_return_if_fail (session != NULL); - if (getuid () == 0) - ck_lock_session (session->priv->console_kit_cookie); +const gchar * +session_get_username (Session *session) +{ + g_return_val_if_fail (session != NULL, NULL); + return session->priv->username; } -void -session_unlock (Session *session) -{ - g_return_if_fail (session != NULL); - if (getuid () == 0) - ck_unlock_session (session->priv->console_kit_cookie); +const gchar * +session_get_console_kit_cookie (Session *session) +{ + g_return_val_if_fail (session != NULL, NULL); + return session->priv->console_kit_cookie; } void -session_stop (Session *session) +session_respond (Session *session, struct pam_response *response) { + int i; + g_return_if_fail (session != NULL); - if (process_get_is_running (PROCESS (session))) + for (i = 0; i < session->priv->messages_length; i++) { - SESSION_GET_CLASS (session)->cleanup (session); - process_signal (PROCESS (session), SIGTERM); + int error = PAM_SUCCESS; + write_data (session, &error, sizeof (error)); + write_string (session, response[i].resp); + write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode)); } + + /* Delete the old messages */ + for (i = 0; i < session->priv->messages_length; i++) + g_free ((char *) session->priv->messages[i].msg); + g_free (session->priv->messages); + session->priv->messages = NULL; + session->priv->messages_length = 0; } -gboolean -session_get_is_stopped (Session *session) +void +session_respond_error (Session *session, int error) { - g_return_val_if_fail (session != NULL, TRUE); - return !process_get_is_running (PROCESS (session)); + g_return_if_fail (session != NULL); + g_return_if_fail (error != PAM_SUCCESS); + + write_data (session, &error, sizeof (error)); } -static gboolean -session_setup (Session *session) +int +session_get_messages_length (Session *session) { - return TRUE; + g_return_val_if_fail (session != NULL, 0); + return session->priv->messages_length; } -static void -session_cleanup (Session *session) +const struct pam_message * +session_get_messages (Session *session) { + g_return_val_if_fail (session != NULL, NULL); + return session->priv->messages; } -static void -setup_log_file (Session *session) +gboolean +session_get_is_authenticated (Session *session) { - int fd; - - /* Redirect output to logfile */ - if (!session->priv->log_file) - return; - - fd = g_open (session->priv->log_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd < 0) - g_warning ("Failed to open log file %s: %s", session->priv->log_file, g_strerror (errno)); - else - { - dup2 (fd, STDERR_FILENO); - close (fd); - } + g_return_val_if_fail (session != NULL, FALSE); + return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS; } -static void -session_run (Process *process) +int +session_get_authentication_result (Session *session) { - Session *session = SESSION (process); - User *user; - int fd; + g_return_val_if_fail (session != NULL, 0); + return session->priv->authentication_result; +} - /* No input and output */ - fd = g_open ("/dev/null", O_RDONLY); - dup2 (fd, STDIN_FILENO); - dup2 (fd, STDOUT_FILENO); - close (fd); +const gchar * +session_get_authentication_result_string (Session *session) +{ + g_return_val_if_fail (session != NULL, NULL); + return session->priv->authentication_result_string; +} - /* Redirect output to logfile */ - if (!session->priv->log_file_as_user) - setup_log_file (session); +void +session_run (Session *session, gchar **argv) +{ + gsize i, argc; + gchar *command, *filename; + GList *link; - /* Make this process its own session */ - if (setsid () < 0) - g_warning ("Failed to make process a new session: %s", strerror (errno)); + g_return_if_fail (session != NULL); + g_return_if_fail (session_get_is_authenticated (session)); - user = pam_session_get_user (session->priv->authentication); + command = g_strjoinv (" ", argv); + g_debug ("Session %d running command %s", session->priv->pid, command); + g_free (command); - /* Change to this user */ - if (getuid () == 0) + /* Create authority location */ + if (session->priv->xauth_use_system_location) { - if (initgroups (user_get_name (user), user_get_gid (user)) < 0) - { - g_warning ("Failed to initialize supplementary groups for %s: %s", user_get_name (user), strerror (errno)); - _exit (EXIT_FAILURE); - } + gchar *run_dir, *dir; - if (setgid (user_get_gid (user)) != 0) - { - g_warning ("Failed to set group ID to %d: %s", user_get_gid (user), strerror (errno)); - _exit (EXIT_FAILURE); - } + run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory"); + dir = g_build_filename (run_dir, session->priv->username, NULL); + g_free (run_dir); - if (setuid (user_get_uid (user)) != 0) + g_mkdir_with_parents (dir, S_IRWXU); + if (getuid () == 0) { - g_warning ("Failed to set user ID to %d: %s", user_get_uid (user), strerror (errno)); - _exit (EXIT_FAILURE); + if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0) + g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno)); } - } - /* Change working directory */ - /* NOTE: This must be done after the permissions are changed because NFS filesystems can - * be setup so the local root user accesses the NFS files as 'nobody'. If the home directories - * are not system readable then the chdir can fail */ - if (chdir (user_get_home_directory (user)) != 0) - { - g_warning ("Failed to change to home directory %s: %s", user_get_home_directory (user), strerror (errno)); - _exit (EXIT_FAILURE); + filename = g_build_filename (dir, "xauthority", NULL); + g_free (dir); } + else + filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL); + + write_string (session, session->priv->log_filename); + write_string (session, filename); + g_free (filename); + argc = g_list_length (session->priv->env); + write_data (session, &argc, sizeof (argc)); + for (link = session->priv->env; link; link = link->next) + write_string (session, (gchar *) link->data); + argc = g_strv_length (argv); + write_data (session, &argc, sizeof (argc)); + for (i = 0; i < argc; i++) + write_string (session, argv[i]); + + session->priv->console_kit_cookie = read_string_from_child (session); +} - /* Redirect output to logfile */ - if (session->priv->log_file_as_user) - setup_log_file (session); - - /* Do PAM actions requiring session process */ - pam_session_setup (session->priv->authentication); - set_env_from_authentication (session, session->priv->authentication); - set_locale (session); - insert_utility_path (session); +void +session_lock (Session *session) +{ + g_return_if_fail (session != NULL); + if (getuid () == 0) + ck_lock_session (session->priv->console_kit_cookie); +} - PROCESS_CLASS (session_parent_class)->run (process); +void +session_unlock (Session *session) +{ + g_return_if_fail (session != NULL); + if (getuid () == 0) + ck_unlock_session (session->priv->console_kit_cookie); } -static void -session_stopped (Process *process) +void +session_stop (Session *session) { - Session *session = SESSION (process); - - pam_session_close (session->priv->authentication); - if (getuid () == 0 && session->priv->console_kit_cookie) - ck_close_session (session->priv->console_kit_cookie); + g_return_if_fail (session != NULL); + + if (session->priv->pid > 0) + { + g_debug ("Session %d: Sending SIGTERM", session->priv->pid); + kill (session->priv->pid, SIGTERM); + // FIXME: Handle timeout + } +} - PROCESS_CLASS (session_parent_class)->stopped (process); +gboolean +session_get_is_stopped (Session *session) +{ + g_return_val_if_fail (session != NULL, TRUE); + return session->priv->pid == 0; } static void session_init (Session *session) { session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate); - session->priv->console_kit_parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); - process_set_clear_environment (PROCESS (session), TRUE); } static void session_finalize (GObject *object) { - Session *self; - - self = SESSION (object); - - g_free (self->priv->log_file); - if (self->priv->authentication) - g_object_unref (self->priv->authentication); - g_free (self->priv->command); - g_hash_table_unref (self->priv->console_kit_parameters); + Session *self = SESSION (object); + int i; + + if (self->priv->pid) + kill (self->priv->pid, SIGKILL); + if (self->priv->from_child_channel) + g_io_channel_unref (self->priv->from_child_channel); + if (self->priv->from_child_watch) + g_source_remove (self->priv->from_child_watch); + if (self->priv->child_watch) + g_source_remove (self->priv->child_watch); + g_free (self->priv->username); + if (self->priv->user) + g_object_unref (self->priv->user); + for (i = 0; i < self->priv->messages_length; i++) + g_free ((char *) self->priv->messages[i].msg); + g_free (self->priv->messages); + g_free (self->priv->authentication_result_string); + g_free (self->priv->log_filename); + g_free (self->priv->class); + g_free (self->priv->tty); + g_free (self->priv->xdisplay); + if (self->priv->xauthority) + g_object_unref (self->priv->xauthority); + g_free (self->priv->remote_host_name); g_free (self->priv->console_kit_cookie); + g_list_free_full (self->priv->env, g_free); G_OBJECT_CLASS (session_parent_class)->finalize (object); } @@ -497,14 +619,35 @@ static void session_class_init (SessionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - ProcessClass *process_class = PROCESS_CLASS (klass); - klass->start = session_real_start; - klass->setup = session_setup; - klass->cleanup = session_cleanup; - process_class->run = session_run; - process_class->stopped = session_stopped; object_class->finalize = session_finalize; g_type_class_add_private (klass, sizeof (SessionPrivate)); + + signals[GOT_MESSAGES] = + g_signal_new ("got-messages", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SessionClass, got_messages), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[AUTHENTICATION_COMPLETE] = + g_signal_new ("authentication-complete", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SessionClass, authentication_complete), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[STOPPED] = + g_signal_new ("stopped", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (SessionClass, stopped), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } |