Logo Search packages:      
Sourcecode: ldm version File versions  Download package

ldm.c

/*
 * ldm.c
 * LTSP display manager.
 * Manages spawning a session to a server.
 *
 * (c) Scott Balneaves, sbalneav@ltsp.org,      2007, 2008 
 *     Oliver Grawert, ogra@ubuntu.com,         2005, 2006, 2007
 *     Vagrant Cascadian, vagrant@freegeek.org, 
 *     Gideon Romm, gadi@ltsp.org,              2007, 2008
 *     Warren Togami
 *     Ryan Niebur, RyanRyan52@gmail.com,       2008
 *
 *
 * This software is licensed under the GPL v2 or later.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <glib.h>
#include <glib-object.h>

#include "ldm.h"

#include <config.h>
#include <libintl.h>
#include <locale.h>
#define _(text) gettext(text)


struct ldm_info ldm;
int    logfd;
FILE  *ldmlog;

void
usage()
{
    fprintf(stderr, "Usage: ldm <vt[1-N]> <:[0-N]> [xserver options]\n");
    exit(1);
}

/*
 * die()
 *
 * Close display manager down with an error message.
 */

void
die(char *msg)
{
    fprintf(ldmlog, "%s\n", msg);

    /*
     * Shut things down gracefully if we can
     */

    if (ldm.greeterpid) {
        close_greeter();
    }
    if (ldm.sshpid) {
        ssh_endsession();
    }
    if (ldm.xserverpid) {
        kill(ldm.xserverpid, SIGTERM);      /* Kill Xorg server off */
        ldm_wait(ldm.xserverpid);
    }

    fclose(ldmlog);
    close(logfd);
    exit(1);
}

/*
 * ldm_spawn:
 *
 * Execute commands.  Prints nice error message if failure.
 */

GPid
ldm_spawn (gchar *command, gint *rfd, gint *wfd,  GSpawnChildSetupFunc setup,
           gpointer data)
{
    GPid pid;
    GError *error = NULL;
    GSpawnFlags flags = G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD;
    gint argc;
    gchar **argv = NULL;

    g_shell_parse_argv(command, &argc, &argv, NULL);

    if (!wfd) {
        flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
    }

    g_spawn_async_with_pipes(
                  NULL,             /* Working directory: inherit */
                  argv,             /* Arguments, null term */
                  NULL,             /* Environment, inherit from parent */
                  flags,            /* Flags, set above */
                  setup,            /* Child setup function: passed to us */
                  data,             /* user_data, passed to us */
                  &pid,             /* child pid */
                  wfd,              /* Pointer to in file descriptor */
                  rfd,              /* Pointer to out file descriptor */
                  &logfd,           /* Our logfile file descriptor */
                  &error);          /* GError handler */

    g_strfreev(argv);

    if (error) {
        fprintf(ldmlog, _("ldm_spawn failed to execute: %s\n"), error->message);
        die(_("Exiting ldm"));
    }

    return pid;
}


/*
 * ldm_wait
 *
 * Reap child process
 */

int
ldm_wait(GPid pid)
{
    int status;

    if (waitpid (pid, &status, 0) < 0) {
        die(_("Error: wait() call failed"));
    }
    if (!WIFEXITED (status)) {
        fprintf(ldmlog, _("Process returned no status\n"));
        return 1;
    } else {
        return WEXITSTATUS (status);
    }
}

/*
 * launch_x
 *
 * Launch the Xorg server
 */

void
launch_x(gchar **xserver_args)
{
    gchar *command;
    gchar **ptr = xserver_args;
    gchar *server_args = NULL;

    ptr += 3;

    if (*ptr) {
        server_args = g_strjoinv(" ", ptr);
    } else {
        server_args = g_strdup("");
    }

    /* Spawn the X server */
    command = g_strjoin(" ", "X", "-auth", ldm.authfile, "-br", "-noreset",
            server_args, ldm.vty, ldm.display, NULL);

    fprintf(ldmlog, _("Launching X as: %s\n"), command);
    /* Pass logfd as stdout so we get X messages */
    ldm.xserverpid = ldm_spawn(command, NULL, &logfd, NULL, NULL);
    g_free(server_args);
    g_free(command);
}

/*
 * rc_files
 *
 * Run startup commands.
 */

void
rc_files(char *action)
{
    GPid rcpid;
    gchar *command;

    command = g_strjoin(" ", "/bin/sh",  RC_DIR "/ldm-script", action, NULL);

    fprintf(ldmlog, "rc_files: %s\n", command);
    rcpid = ldm_spawn(command, NULL, NULL, NULL, NULL);
    ldm_wait(rcpid);
    g_free(command);
}

/*
 * x_session
 *
 * Start a login session with the server
 */

void
x_session()
{
    gchar *command;
    gchar *display = NULL;
    gchar *sound = NULL;
    gchar *lang = NULL;
    gchar *localdev = NULL;
    gchar *client_env = NULL;
    gchar *esdcmd = "esd -nobeeps -public -tcp";
    GPid xsessionpid;
    GPid esdpid = 0;

    /*
     * Set up the LTSP_CLIENT environment variable.
     * We may not want to force set this:
     * FIXME:  Revisit this at some point.
     */

    client_env = g_strconcat("LTSP_CLIENT=", ldm.ipaddr, NULL);

    /*
     * Set the DISPLAY env, if not running over encrypted ssh
     */

    if (ldm.directx) {
        display = g_strconcat("DISPLAY=", ldm.ipaddr, ldm.display, NULL);
    }

    /*
     * Set our language, if a different one is picked.
     */

    if (ldm.lang) {
        lang = g_strconcat("LC_ALL=", ldm.lang, " LANGUAGE=", ldm.lang,
                           " LANG=", ldm.lang, NULL);
    }

    /*
     * Handle sound
     */

    if (ldm.sound) {
        if (!ldm.sound_daemon || !strncmp(ldm.sound_daemon, "pulse", 5)) {
            sound = g_strconcat("PULSE_SERVER=tcp:", ldm.ipaddr,
                    ":4713 ESPEAKER=", ldm.ipaddr, ":16001", NULL);
        } else if (!strncmp(ldm.sound_daemon, "esd", 3)) {
            sound = g_strconcat("ESPEAKER=", ldm.ipaddr, ":16001", NULL);
            esdpid = ldm_spawn(esdcmd, NULL, NULL, NULL, NULL); /* launch ESD */
        } else if (!strncmp(ldm.sound_daemon, "nasd", 4)) {
            sound = g_strconcat("AUDIOSERVER=", ldm.ipaddr, ":0", NULL);
        }
    }

    /*
     * Handle localdev
     */

    if (ldm.localdev) {
        localdev = "; /usr/sbin/ltspfsmounter all cleanup";
    }

    /*
     * FIXME: ditch the kill -1 and use ssh -o exit on the control socket 
     */
    command = g_strjoin(" ", "ssh", "-Y", "-t", "-S", ldm.control_socket,
            "-l", ldm.username, ldm.server, client_env,
            lang ? lang : "", display ? display : "", sound ? sound : "",
            ldm.xsession, ldm.session, localdev ? localdev : "",
            "; kill -1 $PPID", NULL);

    fprintf(ldmlog, _("x_session: %s\n"), command);
    xsessionpid = ldm_spawn(command, NULL, NULL, NULL, NULL);
    ldm_wait(xsessionpid);
    if (esdpid) {
        kill(esdpid, SIGTERM);
        ldm_wait(esdpid);
        esdpid = 0;
    }
    g_free(lang);
    g_free(display);
    g_free(sound);
    g_free(client_env);
    g_free(command);

}

/*
 * Load guest info
 */

void
load_guestinfo()
{
       char **hosts_char = NULL;
       gchar *autoservers = NULL;

       /* Get all info for autologin, without greeter */
       fprintf(ldmlog, _("Logging in as guest\n"));
       ldm.username = g_strdup(getenv("LDM_USERNAME"));
       ldm.password = g_strdup(getenv("LDM_PASSWORD"));
       if (!ldm.username) {
           gchar hostname[HOST_NAME_MAX + 1];      /* +1 for \0 terminator */
           gethostname(hostname, sizeof hostname);
           ldm.username = g_strdup(hostname);
       }
       if (!ldm.password) {
           ldm.password = g_strdup(ldm.username);
       }

       autoservers = g_strdup(getenv("LDM_GUEST_SERVER"));
       if (!autoservers) {
           autoservers = g_strdup(getenv("LDM_AUTOLOGIN_SERVER"));
       }
       if (!autoservers) {
           autoservers = g_strdup(getenv("LDM_SERVER"));
       }

       /*
        * Make sure that if there are multiple servers in the list
        * always take the first one
        */

        hosts_char = g_strsplit(autoservers, " ", -1);

        if ( hosts_char[0] != NULL ) {
            ldm.server = g_strdup(hosts_char[0]);
        }
        return;
}

/*
 * mainline
 */

int
main(int argc, char *argv[])
{
    /* decls */
    gchar *display_env, *server_env, *socket_env, *user_env;
    gchar *err_msg = NULL;


#ifdef ENABLE_NLS
    setlocale (LC_ALL, "");
    bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
    textdomain (GETTEXT_PACKAGE);
#endif

    g_type_init();

    /*
     * Zero out our info struct.
     */

    bzero(&ldm, sizeof ldm);

    /*
     * Process command line args.  Need to get our vt, and our display number
     * Since we don't have any fancy args, we won't bother to do this with
     * getopt, rather, we'll just do it manually.
     */

    if (argc < 3) {
        usage();
    }

    if (strncmp(argv[1], "vt", 2)) {         /* sanity */
        usage();
    }
    if (*argv[2] != ':') {                   /* more sanity */
        usage();
    }

    ldm.vty = g_strdup(argv[1]);
    ldm.display = g_strdup(argv[2]);


    /*
     * Open our log.  We want both a fd (for ldm_spawn's to log to) and
     * a FILE * (for nice fprintf's), so open the log with open(), then
     * use fdopen to obtain a FILE *
     * FIXME: Move to syslog, investigate new syslog interface.
     */

    if ((logfd = open("/var/log/ldm.log",
                      O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0) {
        fprintf(stderr, "Couldn't open logfile\n");
        exit(1);
    }

    if (!(ldmlog = fdopen(logfd, "a"))) {
        fprintf(stderr, _("Couldn't fdopen ldmlog\n"));
        exit(1);
    }

    setbuf(ldmlog, NULL);      /* Unbuffered */

    /*
     * Get our IP address.
     */

    get_ipaddr();
    fprintf(ldmlog, _("LDM2 running on ip address %s\n"), ldm.ipaddr);

    /*
     *  Put ip address in environment so that it is available to to the greeter
     */

    setenv("LDMINFO_IPADDR", ldm.ipaddr, 1);

    /*
     * Get some of the environment variables we'll need.
     */

    ldm.allowguest = ldm_getenv_bool("LDM_GUESTLOGIN");
    ldm.sound = ldm_getenv_bool("SOUND");
    ldm.sound_daemon = g_strdup(getenv("SOUND_DAEMON"));
    ldm.localdev = ldm_getenv_bool("LOCALDEV");
    ldm.override_port = g_strdup(getenv("SSH_OVERRIDE_PORT"));
    ldm.directx = ldm_getenv_bool("LDM_DIRECTX");
    ldm.autologin = ldm_getenv_bool("LDM_AUTOLOGIN");
    ldm.lang = g_strdup(getenv("LDM_LANGUAGE"));
    ldm.session = g_strdup(getenv("LDM_SESSION"));
    ldm.xsession = g_strdup(getenv("LDM_XSESSION"));
    ldm.greeter_prog = g_strdup(getenv("LDM_GREETER"));
    if (!ldm.greeter_prog) {
        ldm.greeter_prog = g_strdup(LDM_EXEC_DIR "/ldmgtkgreet");
    }
    ldm.authfile = g_strdup(getenv("XAUTHORITY"));

    display_env = g_strconcat("DISPLAY=", ldm.display, NULL);

    /*
     * Update our environment with a few extra variables.
     */

    putenv(display_env);

    /*
     * Begin running display manager
     */

    fprintf(ldmlog, _("Launching Xorg\n"));
    launch_x(argv);         /* Launch X, pass any command line args */

    rc_files("init");                      /* Execute any rc files */

    if (!ldm.autologin) {
        gint rfd, wfd;
        fprintf(ldmlog, _("Spawning greeter: %s\n"), ldm.greeter_prog);
        ldm.greeterpid = ldm_spawn(ldm.greeter_prog, &rfd, &wfd, NULL, NULL);
        /* create GIOChannels for the greeter */
        ldm.greeterr = g_io_channel_unix_new(rfd);
        ldm.greeterw = g_io_channel_unix_new(wfd);

        /* ask greeter to fill ldm.username and ldm.server */
        if (get_userid()) {
            die(_("ERROR: get_userid from greeter failed"));
        }

      if(!ldm.autologin) {
          if (get_passwd()) {
            die(_("ERROR: get_passwd from greeter failed"));
          }
      }

        if (get_host()) {
            die(_("ERROR: get_host from greeter failed"));
        }

        if (get_language()) {
            die(_("ERROR: get_language from greeter failed"));
        }

        if (get_session()) {
            die(_("ERROR: get_session from greeter failed"));
        }
    }

    if (ldm.autologin) {
        load_guestinfo();
    }

    /* Verify that we have all info needed to connect */
    if (!ldm.username) {
        err_msg = g_strconcat(_("ERROR: no username"), "\n", NULL );
    }
    if (!ldm.password) {
        err_msg = g_strconcat(_("ERROR: no password"), "\n", NULL );
    }
    if (!ldm.server) {
        err_msg = g_strconcat(_("ERROR: no server"), "\n", NULL );
    }
    if (!ldm.session) {
        ldm.session = g_strdup("default");
    }
    if (!ldm.xsession) {
        err_msg = g_strconcat(_("ERROR: no Xsession"), "\n", NULL );
    }

    if (err_msg) {
        fprintf(ldmlog, "%s", err_msg);
        die(_("Fatal error, missing mandatory information"));
    }

    /*
     * If we run multiple ldm sessions on multiply vty's we need separate
     * control sockets.
     */

    ldm.control_socket = g_strconcat("/var/run/ldm_socket_",
            ldm.vty, "_", ldm.server, NULL);
    socket_env = g_strconcat("LDM_SOCKET=", ldm.control_socket, NULL);
    server_env = g_strconcat("LDM_SERVER=", ldm.server, NULL);
    user_env = g_strconcat("LDM_USERNAME=", ldm.username, NULL);
    putenv(socket_env);
    putenv(server_env);
    putenv(user_env);


    ssh_session();                          /* Log in via ssh */

    if (ldm.greeterpid) {
        close_greeter();
    }

    /*
     * Clear out the password so it's not sitting in memory anywhere
     */

    g_free(ldm.password);

    fprintf(ldmlog, _("Established ssh session.\n"));

    fprintf(ldmlog, _("Executing rc files.\n"));
    rc_files("start");                      /* Execute any rc files */
    fprintf(ldmlog, _("Beginning X session.\n"));
    x_session();                            /* Start X session up */
    fprintf(ldmlog, _("X session ended.\n"));

    /* x_session's exited.  So, clean up. */

    fprintf(ldmlog, _("Executing rc files.\n"));
    rc_files("stop");                       /* Execute any rc files */

    fprintf(ldmlog, _("Killing X server.\n"));
    kill(ldm.xserverpid, SIGTERM);      /* Kill Xorg server off */
    ldm_wait(ldm.xserverpid);

    fprintf(ldmlog, _("Ending ssh session.\n"));
    ssh_endsession();                       /* Log out of server */

    fclose(ldmlog);
    close(logfd);
    g_free(ldm.server);
    g_free(ldm.vty);
    g_free(ldm.display);
    g_free(ldm.override_port);
    g_free(ldm.authfile);
    g_free(ldm.username);
    g_free(ldm.lang);
    g_free(ldm.session);
    g_free(ldm.xsession);
    g_free(ldm.sound_daemon);
    g_free(ldm.greeter_prog);
    g_free(ldm.control_socket);
    g_free(ldm.ipaddr);
    g_free(display_env);
    g_free(socket_env);
    g_free(server_env);
    g_free(user_env);

    exit(0);
}

Generated by  Doxygen 1.6.0   Back to index