Back to index

lightdm  1.3.2
Classes | Defines | Enumerations | Functions | Variables
session.c File Reference
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <glib/gstdio.h>
#include <grp.h>
#include <pwd.h>
#include "session.h"
#include "configuration.h"
#include "console-kit.h"

Go to the source code of this file.

Classes

struct  SessionPrivate

Defines

#define MAX_STRING_LENGTH   65535

Enumerations

enum  { GOT_MESSAGES, AUTHENTICATION_COMPLETE, STOPPED, LAST_SIGNAL }

Functions

 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT)
void session_set_log_file (Session *session, const gchar *filename)
void session_set_class (Session *session, const gchar *class)
void session_set_tty (Session *session, const gchar *tty)
void session_set_xdisplay (Session *session, const gchar *xdisplay)
void session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location)
void session_set_remote_host_name (Session *session, const gchar *remote_host_name)
void session_set_env (Session *session, const gchar *name, const gchar *value)
Usersession_get_user (Session *session)
static void write_data (Session *session, const void *buf, size_t count)
static void write_string (Session *session, const char *value)
static ssize_t read_from_child (Session *session, void *buf, size_t count)
static gchar * read_string_from_child (Session *session)
static void session_watch_cb (GPid pid, gint status, gpointer data)
static gboolean from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
gboolean session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive)
const gchar * session_get_username (Session *session)
const gchar * session_get_console_kit_cookie (Session *session)
void session_respond (Session *session, struct pam_response *response)
void session_respond_error (Session *session, int error)
int session_get_messages_length (Session *session)
struct pam_message * session_get_messages (Session *session)
gboolean session_get_is_authenticated (Session *session)
int session_get_authentication_result (Session *session)
const gchar * session_get_authentication_result_string (Session *session)
void session_run (Session *session, gchar **argv)
void session_lock (Session *session)
void session_unlock (Session *session)
void session_stop (Session *session)
gboolean session_get_is_stopped (Session *session)
static void session_init (Session *session)
static void session_finalize (GObject *object)
static void session_class_init (SessionClass *klass)

Variables

static guint signals [LAST_SIGNAL] = { 0 }

Class Documentation

struct SessionPrivate

Definition at line 34 of file session.c.

Collaboration diagram for SessionPrivate:
Class Members
gboolean authentication_complete
int authentication_result
gchar * authentication_result_string
gboolean authentication_started
guint child_watch
gchar * class
gchar * console_kit_cookie
GList * env
GIOChannel * from_child_channel
int from_child_output
guint from_child_watch
gchar * log_filename
struct pam_message * messages
int messages_length
GPid pid
gchar * remote_host_name
int to_child_input
gchar * tty
User * user
gchar * username
gboolean xauth_use_system_location
XAuthority * xauthority
gchar * xdisplay

Define Documentation

#define MAX_STRING_LENGTH   65535

Definition at line 87 of file session.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
GOT_MESSAGES 
AUTHENTICATION_COMPLETE 
STOPPED 
LAST_SIGNAL 

Definition at line 26 of file session.c.


Function Documentation

static gboolean from_child_cb ( GIOChannel *  source,
GIOCondition  condition,
gpointer  data 
) [static]

Definition at line 240 of file session.c.

{
    Session *session = data;
    gchar *username;
    ssize_t n_read;
    gboolean auth_complete;

    /* Remote end gone */
    if (condition == G_IO_HUP)
    {
        session->priv->from_child_watch = 0;
        return FALSE;
    }

    /* 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);

    /* 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)
    {
        session->priv->from_child_watch = 0;
        return FALSE;
    }

    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_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string);

        /* No longer expect any more messages */
        session->priv->from_child_watch = 0;

        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);
        }

        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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

G_DEFINE_TYPE ( Session  ,
session  ,
G_TYPE_OBJECT   
)
static ssize_t read_from_child ( Session session,
void *  buf,
size_t  count 
) [static]

Definition at line 181 of file session.c.

{
    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;
}

Here is the caller graph for this function:

static gchar* read_string_from_child ( Session session) [static]

Definition at line 191 of file session.c.

{
    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';      

    return value;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void session_class_init ( SessionClass klass) [static]

Definition at line 619 of file session.c.

{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);

    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);
}

Here is the call graph for this function:

static void session_finalize ( GObject *  object) [static]

Definition at line 585 of file session.c.

{
    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);
}

Here is the caller graph for this function:

Definition at line 478 of file session.c.

{
    g_return_val_if_fail (session != NULL, 0);
    return session->priv->authentication_result;
}

Here is the caller graph for this function:

Definition at line 485 of file session.c.

{
    g_return_val_if_fail (session != NULL, NULL);
    return session->priv->authentication_result_string;
}

Here is the caller graph for this function:

const gchar* session_get_console_kit_cookie ( Session session)

Definition at line 418 of file session.c.

{
    g_return_val_if_fail (session != NULL, NULL);
    return session->priv->console_kit_cookie;
}
gboolean session_get_is_authenticated ( Session session)

Definition at line 471 of file session.c.

{
    g_return_val_if_fail (session != NULL, FALSE);
    return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
}

Here is the caller graph for this function:

gboolean session_get_is_stopped ( Session session)

Definition at line 572 of file session.c.

{
    g_return_val_if_fail (session != NULL, TRUE);
    return session->priv->pid == 0;
}

Here is the caller graph for this function:

struct pam_message* session_get_messages ( Session session) [read]

Definition at line 464 of file session.c.

{
    g_return_val_if_fail (session != NULL, NULL);
    return session->priv->messages;
}

Here is the caller graph for this function:

Definition at line 457 of file session.c.

{
    g_return_val_if_fail (session != NULL, 0);
    return session->priv->messages_length;
}

Here is the caller graph for this function:

User* session_get_user ( Session session)

Definition at line 149 of file session.c.

{
    g_return_val_if_fail (session != NULL, NULL);

    if (session->priv->username == NULL)
        return NULL;

    if (!session->priv->user)
        session->priv->user = accounts_get_user_by_name (session->priv->username);

    return session->priv->user;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const gchar* session_get_username ( Session session)

Definition at line 411 of file session.c.

{
    g_return_val_if_fail (session != NULL, NULL);
    return session->priv->username;
}

Here is the caller graph for this function:

static void session_init ( Session session) [static]

Definition at line 579 of file session.c.

{
    session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
}
void session_lock ( Session session)

Definition at line 543 of file session.c.

{    
    g_return_if_fail (session != NULL);
    if (getuid () == 0)
        ck_lock_session (session->priv->console_kit_cookie);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void session_respond ( Session session,
struct pam_response *  response 
)

Definition at line 425 of file session.c.

{
    int error = PAM_SUCCESS;
    int i;

    g_return_if_fail (session != NULL);

    write_data (session, &error, sizeof (error));
    for (i = 0; i < session->priv->messages_length; i++)
    {
        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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void session_respond_error ( Session session,
int  error 
)

Definition at line 448 of file session.c.

{
    g_return_if_fail (session != NULL);
    g_return_if_fail (error != PAM_SUCCESS);

    write_data (session, &error, sizeof (error));  
}

Here is the call graph for this function:

Here is the caller graph for this function:

void session_run ( Session session,
gchar **  argv 
)

Definition at line 492 of file session.c.

{
    gsize i, argc;
    gchar *command, *filename;
    GList *link;

    g_return_if_fail (session != NULL);
    g_return_if_fail (session_get_is_authenticated (session));

    command = g_strjoinv (" ", argv);
    g_debug ("Session %d running command %s", session->priv->pid, command);
    g_free (command);

    /* Create authority location */
    if (session->priv->xauth_use_system_location)
    {
        gchar *run_dir, *dir;

        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);

        g_mkdir_with_parents (dir, S_IRWXU);
        if (getuid () == 0)
        {
            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));
        }

        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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void session_set_class ( Session session,
const gchar *  class 
)

Definition at line 100 of file session.c.

{
    g_return_if_fail (session != NULL);
    g_free (session->priv->class);
    session->priv->class = g_strdup (class);
}

Here is the caller graph for this function:

void session_set_env ( Session session,
const gchar *  name,
const gchar *  value 
)

Definition at line 142 of file session.c.

{
    g_return_if_fail (session != NULL);
    session->priv->env = g_list_append (session->priv->env, g_strdup_printf ("%s=%s", name, value));
}

Here is the caller graph for this function:

void session_set_log_file ( Session session,
const gchar *  filename 
)

Definition at line 92 of file session.c.

{
    g_return_if_fail (session != NULL);
    g_free (session->priv->log_filename);
    session->priv->log_filename = g_strdup (filename);
}

Here is the caller graph for this function:

void session_set_remote_host_name ( Session session,
const gchar *  remote_host_name 
)

Definition at line 134 of file session.c.

{
    g_return_if_fail (session != NULL);
    g_free (session->priv->remote_host_name);
    session->priv->remote_host_name = g_strdup (remote_host_name);
}

Here is the caller graph for this function:

void session_set_tty ( Session session,
const gchar *  tty 
)

Definition at line 108 of file session.c.

{
    g_return_if_fail (session != NULL);
    g_free (session->priv->tty);
    session->priv->tty = g_strdup (tty);
}

Here is the caller graph for this function:

void session_set_xauthority ( Session session,
XAuthority authority,
gboolean  use_system_location 
)

Definition at line 124 of file session.c.

{
    g_return_if_fail (session != NULL);
    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;
}

Here is the caller graph for this function:

void session_set_xdisplay ( Session session,
const gchar *  xdisplay 
)

Definition at line 116 of file session.c.

{
    g_return_if_fail (session != NULL);
    g_free (session->priv->xdisplay);
    session->priv->xdisplay = g_strdup (xdisplay);
}

Here is the caller graph for this function:

gboolean session_start ( Session session,
const gchar *  service,
const gchar *  username,
gboolean  do_authenticate,
gboolean  is_interactive 
)

Definition at line 316 of file session.c.

{
    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);

    /* Create pipes to talk to the child */
    if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
    {
        g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
        return FALSE;
    }
    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)
    {
        g_debug ("Failed to fork session child process: %s", strerror (errno));
        return FALSE;
    }
    if (session->priv->pid == 0)
    {
        /* 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);
    }

    /* Listen for session termination */
    session->priv->authentication_started = TRUE;
    session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);

    /* Close the ends of the pipes we don't need */
    close (to_child_output);
    close (from_child_input);
  
    /* 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)
    {
        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);    

    g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, service, username);

    return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void session_stop ( Session session)

Definition at line 559 of file session.c.

{
    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
    }
}

Here is the caller graph for this function:

void session_unlock ( Session session)

Definition at line 551 of file session.c.

{    
    g_return_if_fail (session != NULL);
    if (getuid () == 0)
        ck_unlock_session (session->priv->console_kit_cookie);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void session_watch_cb ( GPid  pid,
gint  status,
gpointer  data 
) [static]

Definition at line 214 of file session.c.

{
    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);
}

Here is the caller graph for this function:

static void write_data ( Session session,
const void *  buf,
size_t  count 
) [static]

Definition at line 163 of file session.c.

{
    if (write (session->priv->to_child_input, buf, count) != count)
        g_warning ("Error writing to session: %s", strerror (errno));
}

Here is the caller graph for this function:

static void write_string ( Session session,
const char *  value 
) [static]

Definition at line 170 of file session.c.

{
    int length;

    length = value ? strlen (value) : -1;
    write_data (session, &length, sizeof (length));
    if (value)
        write_data (session, value, sizeof (char) * length);
}

Here is the call graph for this function:


Variable Documentation

guint signals[LAST_SIGNAL] = { 0 } [static]

Definition at line 32 of file session.c.