Logo Search packages:      
Sourcecode: ldm version File versions

sshutils.c

/*
 * sshutils.c
 * LTSP display manager.
 * Manages spawning a session to a server.
 *
 * (c) Scott Balneaves, sbalneav@ltsp.org
 *
 * This software is licensed under the GPL v2 or later.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <pty.h>
#include <utmp.h>
#include <glib.h>

#include "ldm.h"

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

#define ERROR -1
#define TIMED_OUT -2

int
expect(int fd, char *p, int seconds, ...)
{
    fd_set set;
    struct timeval timeout;
    int i, st;
    ssize_t size = 0;
    size_t total = 0;
    va_list ap;
    char buffer[BUFSIZ];
    gchar *arg;
    GPtrArray *expects;
    int loopcount = seconds;
    int loopend = 0;

    bzero(p, MAXEXP);

    expects = g_ptr_array_new();

    va_start(ap, seconds);

    while ((arg = va_arg(ap, char *)) != NULL) {
        g_ptr_array_add(expects, (gpointer) arg);
    }

    va_end(ap);

    /*
     * Set our file descriptor to be watched.
     */


    /*
     * Main loop.
     */

    while(1) {
        timeout.tv_sec = (long)1;             /* one second timeout */
        timeout.tv_usec = 0;

        FD_ZERO(&set);
        FD_SET(fd, &set);
        st = select(FD_SETSIZE, &set, NULL, NULL, &timeout);

        if (child_exited) {
            break;                  /* someone died on us */
        }

        if (st < 0) {                 /* bad thing */
            break;
        }

        if (loopcount == 0) {
            break;
        }

        if (!st) {                  /* timeout */
            loopcount--;            /* We've not seen the data we want */
            continue;
        }

        size = read(fd, buffer, sizeof buffer);
        if (size <= 0) {
            break;
        }

        if ((total + size) < MAXEXP) {
            strncpy(p + total, buffer, size);
            total += size;
        }

        for (i = 0; i < expects->len; i++) {
            if (strstr(p, g_ptr_array_index(expects, i))) {
                loopend = TRUE;
                break;
            }
        }

        if (loopend) {
            break;
        }

        if (timeout.tv_sec == 0) {
            break;
        }
    }

    loginfo(_("expect saw: %s"), p);

    if (size < 0 || st < 0 || child_exited) {
        return ERROR;               /* error occured */
    }
    if (loopcount == 0) {
        return TIMED_OUT;           /* timed out */
    } else {
        return i;                   /* which expect did we see? */
    }
}

void
ssh_chat(gint fd)
{
    int seen;
    gchar lastseen[MAXEXP];
    int first_time = 1;

    /* We've already got the password here from the mainline,  so there's
     * no delay between asking for the userid, and the ssh session asking for a
     * password.  That's why we need the "first_time" variable.  If a
     * password expiry is in the works, then subsequent password prompts
     * will cause us to go back to the greeter. */

    child_exited = FALSE;

    while (TRUE) {
        /* ASSUMPTION: ssh will send out a string that ends in ": " for an expiry */
        seen = expect(fd, lastseen, 30, SENTINEL, ": ", NULL);

        /* We might have a : in the data, we're looking for :'s at the
           end of the line */
        if (seen == 0) {
            loginfo(_("Logged in successfully.\n"));
            g_free(ldm.password);
            ldm.password = NULL;
            return;
        } else if (seen == 1) {
            int i;
            g_strdelimit(lastseen, "\r\n\t", ' ');
            g_strchomp(lastseen);
            i = strlen(lastseen);
            /* If it's not the first time through, or the :'s not at the
             * end of a line (password expiry or error), set the message */
            if ((!first_time) || (lastseen[i - 1] != ':')) {
                set_message(lastseen);
            }
            /* If ':' *IS* the last character on the line, we'll assume a
             * password prompt is presented, and get a password */
            if (lastseen[i - 1] == ':') {
                if (!first_time) {    /* first time, we already prompted */
                    get_passwd();
                }
                write(fd, ldm.password, strlen(ldm.password));
                write(fd, "\n", 1);
                g_free(ldm.password);
                ldm.password = NULL;
            }
            first_time = 0;
        } else if (seen < 0) {
            set_message(_("No response from server, restarting..."));
            sleep(5);
            die(_("No response, restarting"));
        }
    }
}

/*
 * ssh_session()
 * Start an ssh login to the server.
 */

void
ssh_tty_init(void)
{
    (void) setsid();
    if (login_tty(ldm.sshslavefd) < 0 ) {
        logerr(_("login_tty failed"));
        exit(1);
    }
}

void
ssh_session(void)
{
    gchar *userathost;
    gchar *command;
    gchar *port = NULL;
    GPid pid;

    if (ldm.override_port) {
        port = g_strconcat(" -p ", ldm.override_port, " ",  NULL);
    }

    userathost = g_strconcat(ldm.username, "@", ldm.server, NULL);

    openpty(&ldm.sshfd, &ldm.sshslavefd, NULL, NULL, NULL);

    command = g_strjoin(" ", "ssh", "-Y", "-t", "-M", "-S", ldm.control_socket,
            port ? port : "",
            "-o", "NumberOfPasswordPrompts=1",
            userathost, "echo " SENTINEL "; /bin/sh -", NULL);
    loginfo(_("ssh_session: %s"), command);

    ldm.sshpid = ldm_spawn(command, NULL, NULL, ssh_tty_init);

    ssh_chat(ldm.sshfd);

    if (ldm.override_port) {
        g_free(port);
    }
    g_free(userathost);
}

void
ssh_endsession(void)
{
    GPid pid;
    gchar *command;
    gchar buf[BUFSIZ];
    struct stat stbuf;

    if (!stat(ldm.control_socket, &stbuf)) {
        /* socket still exists, so we need to shut down the ssh link */

        command = g_strjoin(" ", "ssh", "-S", ldm.control_socket, "-O", "exit", ldm.server, NULL);

        loginfo(_("Shutting down ssh session: %s"), command);
        pid = ldm_spawn(command, NULL, NULL, NULL);
        ldm_wait(pid);
        read(ldm.sshfd, buf, sizeof buf);       /* clear any exit message so ssh can exit cleanly */
        ldm_wait(ldm.sshpid);
        ldm.sshpid = 0;
        g_free(command);
    }
}

Generated by  Doxygen 1.6.0   Back to index