# HG changeset patch # User Matt Johnston # Date 1091350441 0 # Node ID b4874d7722105673acbfe06177e5eed512d0d283 # Parent 0883c0906870d3a2a9be3a4fa6afb9e95ef8a19a - Added terminal mode handling etc for the client, and window change - Refactored the terminal-mode handling for the server - Improved session closing for the client diff -r 0883c0906870 -r b4874d772210 chansession.h --- a/chansession.h Fri Jul 30 12:29:53 2004 +0000 +++ b/chansession.h Sun Aug 01 08:54:01 2004 +0000 @@ -39,7 +39,6 @@ int slave; unsigned char * tty; unsigned char * term; - unsigned int termw, termh, termc, termr; /* width, height, col, rows */ /* exit details */ int exited; @@ -76,6 +75,9 @@ struct ChanSess * chansess); void addnewvar(const char* param, const char* var); +void cli_send_chansess_request(); +void cli_tty_cleanup(); + void svr_chansessinitialise(); extern const struct ChanType svrchansess; diff -r 0883c0906870 -r b4874d772210 cli-auth.c --- a/cli-auth.c Fri Jul 30 12:29:53 2004 +0000 +++ b/cli-auth.c Sun Aug 01 08:54:01 2004 +0000 @@ -7,6 +7,8 @@ #include "packet.h" #include "runopts.h" +#undef DROPBEAR_PUBKEY_AUTH + void cli_authinitialise() { memset(&ses.authstate, 0, sizeof(ses.authstate)); diff -r 0883c0906870 -r b4874d772210 cli-chansession.c --- a/cli-chansession.c Fri Jul 30 12:29:53 2004 +0000 +++ b/cli-chansession.c Sun Aug 01 08:54:01 2004 +0000 @@ -6,6 +6,7 @@ #include "channel.h" #include "ssh.h" #include "runopts.h" +#include "termcodes.h" static void cli_closechansess(struct Channel *channel); static int cli_initchansess(struct Channel *channel); @@ -16,7 +17,7 @@ static void send_chansess_shell_req(struct Channel *channel); static void cli_tty_setup(); -static void cli_tty_cleanup(); +void cli_tty_cleanup(); static const struct ChanType clichansess = { 0, /* sepfds */ @@ -50,7 +51,6 @@ } - /* Taken from OpenSSH's sshtty.c: * RCSID("OpenBSD: sshtty.c,v 1.5 2003/09/19 17:43:35 markus Exp "); */ static void cli_tty_setup() { @@ -91,12 +91,13 @@ TRACE(("leave cli_tty_setup")); } -static void cli_tty_cleanup() { +void cli_tty_cleanup() { TRACE(("enter cli_tty_cleanup")); if (cli_ses.tty_raw_mode == 0) { TRACE(("leave cli_tty_cleanup: not in raw mode")); + return; } if (tcsetattr(STDIN_FILENO, TCSADRAIN, &cli_ses.saved_tio) == -1) { @@ -108,30 +109,123 @@ TRACE(("leave cli_tty_cleanup")); } +static void put_termcodes() { + + TRACE(("enter put_termcodes")); + + struct termios tio; + unsigned int sshcode; + const struct TermCode *termcode; + unsigned int value; + unsigned int mapcode; + + unsigned int bufpos1, bufpos2; + + if (tcgetattr(STDIN_FILENO, &tio) == -1) { + dropbear_log(LOG_WARNING, "Failed reading termmodes"); + buf_putint(ses.writepayload, 1); /* Just the terminator */ + buf_putbyte(ses.writepayload, 0); /* TTY_OP_END */ + return; + } + + bufpos1 = ses.writepayload->pos; + buf_putint(ses.writepayload, 0); /* A placeholder for the final length */ + + /* As with Dropbear server, we ignore baud rates for now */ + for (sshcode = 1; sshcode < MAX_TERMCODE; sshcode++) { + + termcode = &termcodes[sshcode]; + mapcode = termcode->mapcode; + + switch (termcode->type) { + + case TERMCODE_NONE: + continue; + + case TERMCODE_CONTROLCHAR: + value = tio.c_cc[mapcode]; + break; + + case TERMCODE_INPUT: + value = tio.c_iflag & mapcode; + break; + + case TERMCODE_OUTPUT: + value = tio.c_oflag & mapcode; + break; + + case TERMCODE_LOCAL: + value = tio.c_lflag & mapcode; + break; + + case TERMCODE_CONTROL: + value = tio.c_cflag & mapcode; + break; + + default: + continue; + + } + + /* If we reach here, we have something to say */ + buf_putbyte(ses.writepayload, sshcode); + buf_putint(ses.writepayload, value); + } + + buf_putbyte(ses.writepayload, 0); /* THE END, aka TTY_OP_END */ + + /* Put the string length at the start of the buffer */ + bufpos2 = ses.writepayload->pos; + + buf_setpos(ses.writepayload, bufpos1); /* Jump back */ + buf_putint(ses.writepayload, bufpos2 - bufpos1); /* len(termcodes) */ + buf_setpos(ses.writepayload, bufpos2); /* Back where we were */ + + TRACE(("leave put_termcodes")); +} + +static void put_winsize() { + + struct winsize ws; + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) { + /* Some sane defaults */ + ws.ws_row = 25; + ws.ws_col = 80; + ws.ws_xpixel = 0; + ws.ws_ypixel = 0; + } + + buf_putint(ses.writepayload, ws.ws_col); /* Cols */ + buf_putint(ses.writepayload, ws.ws_row); /* Rows */ + buf_putint(ses.writepayload, ws.ws_xpixel); /* Width */ + buf_putint(ses.writepayload, ws.ws_ypixel); /* Height */ + +} + static void send_chansess_pty_req(struct Channel *channel) { - unsigned char* termmodes = "\0"; unsigned char* term = NULL; - int termc = 80, termr = 25, termw = 0, termh = 0; /* XXX TODO matt */ TRACE(("enter send_chansess_pty_req")); + start_channel_request(channel, "pty-req"); + /* Don't want replies */ + buf_putbyte(ses.writepayload, 0); + + /* Get the terminal */ term = getenv("TERM"); if (term == NULL) { - term = "vt100"; + term = "vt100"; /* Seems a safe default */ } - - /* XXX TODO */ - buf_putbyte(ses.writepayload, 0); /* Don't want replies */ buf_putstring(ses.writepayload, term, strlen(term)); - buf_putint(ses.writepayload, termc); /* Cols */ - buf_putint(ses.writepayload, termr); /* Rows */ - buf_putint(ses.writepayload, termw); /* Width */ - buf_putint(ses.writepayload, termh); /* Height */ - buf_putstring(ses.writepayload, termmodes, 1); /* XXX TODO */ - //m_free(termmodes); + /* Window size */ + put_winsize(); + + /* Terminal mode encoding */ + put_termcodes(); encrypt_packet(); TRACE(("leave send_chansess_pty_req")); @@ -171,7 +265,6 @@ send_chansess_pty_req(channel); } - cli_opts.cmd = "df"; send_chansess_shell_req(channel); if (cli_opts.wantpty) { diff -r 0883c0906870 -r b4874d772210 cli-main.c --- a/cli-main.c Fri Jul 30 12:29:53 2004 +0000 +++ b/cli-main.c Sun Aug 01 08:54:01 2004 +0000 @@ -61,9 +61,12 @@ cli_opts.remoteport, format); } + /* Do the cleanup first, since then the terminal will be reset */ + cli_session_cleanup(); + common_session_cleanup(); + _dropbear_log(LOG_INFO, fmtbuf, param); - common_session_cleanup(); exit(exitcode); } @@ -73,6 +76,6 @@ vsnprintf(printbuf, sizeof(printbuf), format, param); - fprintf(stderr, "Dropbear: %s\n", printbuf); + fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf); } diff -r 0883c0906870 -r b4874d772210 cli-runopts.c --- a/cli-runopts.c Fri Jul 30 12:29:53 2004 +0000 +++ b/cli-runopts.c Sun Aug 01 08:54:01 2004 +0000 @@ -55,11 +55,12 @@ char* userhostarg = NULL; /* see printhelp() for options */ + cli_opts.progname = argv[0]; cli_opts.remotehost = NULL; cli_opts.remoteport = NULL; cli_opts.username = NULL; cli_opts.cmd = NULL; - cli_opts.wantpty = 0; + cli_opts.wantpty = 1; opts.nolocaltcp = 0; opts.noremotetcp = 0; /* not yet diff -r 0883c0906870 -r b4874d772210 cli-session.c --- a/cli-session.c Fri Jul 30 12:29:53 2004 +0000 +++ b/cli-session.c Sun Aug 01 08:54:01 2004 +0000 @@ -9,10 +9,13 @@ #include "channel.h" #include "random.h" #include "service.h" +#include "runopts.h" +#include "chansession.h" static void cli_remoteclosed(); static void cli_sessionloop(); static void cli_session_init(); +static void cli_finished(); struct clientsession cli_ses; /* GLOBAL */ @@ -163,6 +166,12 @@ cli_ses.state = SESSION_RUNNING; return; + case SESSION_RUNNING: + if (ses.chancount < 1) { + cli_finished(); + } + return; + /* XXX more here needed */ @@ -174,6 +183,26 @@ } +void cli_session_cleanup() { + + if (!sessinitdone) { + return; + } + cli_tty_cleanup(); + +} + +static void cli_finished() { + + cli_session_cleanup(); + common_session_cleanup(); + fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username, + cli_opts.remotehost, cli_opts.remoteport); + exit(EXIT_SUCCESS); +} + + + /* called when the remote side closes the connection */ static void cli_remoteclosed() { diff -r 0883c0906870 -r b4874d772210 dbutil.c --- a/dbutil.c Fri Jul 30 12:29:53 2004 +0000 +++ b/dbutil.c Sun Aug 01 08:54:01 2004 +0000 @@ -103,6 +103,7 @@ #ifdef DEBUG_TRACE void dropbear_trace(const char* format, ...) { +#if 0 va_list param; va_start(param, format); @@ -110,6 +111,7 @@ vfprintf(stderr, format, param); fprintf(stderr, "\n"); va_end(param); +#endif } #endif /* DEBUG_TRACE */ diff -r 0883c0906870 -r b4874d772210 options.h --- a/options.h Fri Jul 30 12:29:53 2004 +0000 +++ b/options.h Sun Aug 01 08:54:01 2004 +0000 @@ -111,7 +111,7 @@ /* Authentication types to enable, at least one required. RFC Draft requires pubkey auth, and recommends password */ #define DROPBEAR_PASSWORD_AUTH -//#define DROPBEAR_PUBKEY_AUTH +#define DROPBEAR_PUBKEY_AUTH /* Random device to use - you must specify _one only_. * DEV_RANDOM is recommended on hosts with a good /dev/urandom, otherwise use diff -r 0883c0906870 -r b4874d772210 runopts.h --- a/runopts.h Fri Jul 30 12:29:53 2004 +0000 +++ b/runopts.h Sun Aug 01 08:54:01 2004 +0000 @@ -79,6 +79,7 @@ /* Uncompleted XXX matt */ typedef struct cli_runopts { + char *progname; char *remotehost; char *remoteport; diff -r 0883c0906870 -r b4874d772210 session.h --- a/session.h Fri Jul 30 12:29:53 2004 +0000 +++ b/session.h Sun Aug 01 08:54:01 2004 +0000 @@ -55,6 +55,7 @@ void cli_session(int sock, char *remotehost); void cli_dropbear_exit(int exitcode, const char* format, va_list param); void cli_dropbear_log(int priority, const char* format, va_list param); +void cli_session_cleanup(); struct key_context { diff -r 0883c0906870 -r b4874d772210 signkey.c --- a/signkey.c Fri Jul 30 12:29:53 2004 +0000 +++ b/signkey.c Sun Aug 01 08:54:01 2004 +0000 @@ -53,7 +53,6 @@ unsigned int len; TRACE(("enter buf_get_pub_key")); - printhex(buf_getptr(buf, 0x99), 0x99); ident = buf_getstring(buf, &len); diff -r 0883c0906870 -r b4874d772210 svr-chansession.c --- a/svr-chansession.c Fri Jul 30 12:29:53 2004 +0000 +++ b/svr-chansession.c Sun Aug 01 08:54:01 2004 +0000 @@ -56,6 +56,7 @@ static void send_exitsignalstatus(struct Channel *channel); static int sesscheckclose(struct Channel *channel); +static void get_termmodes(struct ChanSess *chansess); /* required to clear environment */ @@ -192,10 +193,6 @@ chansess->slave = -1; chansess->tty = NULL; chansess->term = NULL; - chansess->termw = 0; - chansess->termh = 0; - chansess->termc = 0; - chansess->termr = 0; chansess->exited = 0; @@ -376,22 +373,111 @@ * client. Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ static int sessionwinchange(struct ChanSess *chansess) { + int termc, termr, termw, termh; + if (chansess->master < 0) { /* haven't got a pty yet */ return DROPBEAR_FAILURE; } - chansess->termc = buf_getint(ses.payload); - chansess->termr = buf_getint(ses.payload); - chansess->termw = buf_getint(ses.payload); - chansess->termh = buf_getint(ses.payload); + termc = buf_getint(ses.payload); + termr = buf_getint(ses.payload); + termw = buf_getint(ses.payload); + termh = buf_getint(ses.payload); - pty_change_window_size(chansess->master, chansess->termr, chansess->termc, - chansess->termw, chansess->termh); + pty_change_window_size(chansess->master, termr, termc, termw, termh); return DROPBEAR_FAILURE; } +static void get_termmodes(struct ChanSess *chansess) { + + struct termios termio; + unsigned char opcode; + unsigned int value; + const struct TermCode * termcode; + unsigned int len; + + TRACE(("enter get_termmodes")); + + /* Term modes */ + /* We'll ignore errors and continue if we can't set modes. + * We're ignoring baud rates since they seem evil */ + if (tcgetattr(chansess->master, &termio) == -1) { + return; + } + + len = buf_getint(ses.payload); + if (len != ses.payload->len - ses.payload->pos) { + dropbear_exit("bad term mode string"); + } + + if (len == 0) { + TRACE(("leave get_termmodes: empty terminal modes string")); + } + + while (((opcode = buf_getbyte(ses.payload)) != 0x00) && opcode <= 159) { + + /* must be before checking type, so that value is consumed even if + * we don't use it */ + value = buf_getint(ses.payload); + + /* handle types of code */ + if (opcode > MAX_TERMCODE) { + continue; + } + termcode = &termcodes[(unsigned int)opcode]; + + + switch (termcode->type) { + + case TERMCODE_NONE: + break; + + case TERMCODE_CONTROLCHAR: + termio.c_cc[termcode->mapcode] = value; + break; + + case TERMCODE_INPUT: + if (value) { + termio.c_iflag |= termcode->mapcode; + } else { + termio.c_iflag &= ~(termcode->mapcode); + } + break; + + case TERMCODE_OUTPUT: + if (value) { + termio.c_oflag |= termcode->mapcode; + } else { + termio.c_oflag &= ~(termcode->mapcode); + } + break; + + case TERMCODE_LOCAL: + if (value) { + termio.c_lflag |= termcode->mapcode; + } else { + termio.c_lflag &= ~(termcode->mapcode); + } + break; + + case TERMCODE_CONTROL: + if (value) { + termio.c_cflag |= termcode->mapcode; + } else { + termio.c_cflag &= ~(termcode->mapcode); + } + break; + + } + } + if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) { + dropbear_log(LOG_INFO, "error setting terminal attributes"); + } + TRACE(("leave get_termmodes")); +} + /* Set up a session pty which will be used to execute the shell or program. * The pty is allocated now, and kept for when the shell/program executes. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ @@ -399,7 +485,6 @@ unsigned int termlen; unsigned char namebuf[65]; - struct termios termio; TRACE(("enter sessionpty")); chansess->term = buf_getstring(ses.payload, &termlen); @@ -408,10 +493,6 @@ TRACE(("leave sessionpty: term len too long")); return DROPBEAR_FAILURE; } - chansess->termc = buf_getint(ses.payload); - chansess->termr = buf_getint(ses.payload); - chansess->termw = buf_getint(ses.payload); - chansess->termh = buf_getint(ses.payload); /* allocate the pty */ assert(chansess->master == -1); /* haven't already got one */ @@ -426,89 +507,12 @@ } pty_setowner(ses.authstate.pw, chansess->tty); - pty_change_window_size(chansess->master, chansess->termr, chansess->termc, - chansess->termw, chansess->termh); - - /* Term modes */ - /* We'll ignore errors and continue if we can't set modes. - * We're ignoring baud rates since they seem evil */ - if (tcgetattr(chansess->master, &termio) == 0) { - unsigned char opcode; - unsigned int value; - const struct TermCode * termcode; - unsigned int len; - - len = buf_getint(ses.payload); - if (len != ses.payload->len - ses.payload->pos) { - dropbear_exit("bad term mode string"); - } - - if (len == 0) { - TRACE(("empty terminal modes string")); - return DROPBEAR_SUCCESS; - } - - while (((opcode = buf_getbyte(ses.payload)) != 0x00) && - opcode <= 159) { - - /* must be before checking type, so that value is consumed even if - * we don't use it */ - value = buf_getint(ses.payload); - - /* handle types of code */ - if (opcode > MAX_TERMCODE) { - continue; - } - termcode = &termcodes[(unsigned int)opcode]; - - - switch (termcode->type) { - - case TERMCODE_NONE: - break; - case TERMCODE_CONTROLCHAR: - termio.c_cc[termcode->mapcode] = value; - break; - - case TERMCODE_INPUT: - if (value) { - termio.c_iflag |= termcode->mapcode; - } else { - termio.c_iflag &= ~(termcode->mapcode); - } - break; - - case TERMCODE_OUTPUT: - if (value) { - termio.c_oflag |= termcode->mapcode; - } else { - termio.c_oflag &= ~(termcode->mapcode); - } - break; + /* Set up the rows/col counts */ + sessionwinchange(chansess); - case TERMCODE_LOCAL: - if (value) { - termio.c_lflag |= termcode->mapcode; - } else { - termio.c_lflag &= ~(termcode->mapcode); - } - break; - - case TERMCODE_CONTROL: - if (value) { - termio.c_cflag |= termcode->mapcode; - } else { - termio.c_cflag &= ~(termcode->mapcode); - } - break; - - } - } - if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) { - dropbear_log(LOG_INFO, "error setting terminal attributes"); - } - } + /* Read the terminal modes */ + get_termmodes(chansess); TRACE(("leave sessionpty")); return DROPBEAR_SUCCESS;