Add pty mode support code

Pty mode code added so that sshd server can do remote echo, backspace
processing. etc and ssh.exe client does not have to do local echo. We
can enrich it in future for more features and allowing programs like
powershell to run interactive. Pty mode is central for interactive use
and will be built using Windows console instead of termios that
Linux/Unix uses.
This commit is contained in:
quamrulmina 2015-10-12 13:49:15 -05:00
parent b72c36c802
commit 55f2ec6825
5 changed files with 207 additions and 6 deletions

View File

@ -2459,6 +2459,8 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
if ( data[0] == '\033' ) { // escape char octal 33, decimal 27
if ( (data[1] == '[') && (data[2]== '2') && (data[3]== '0') && ( data[4]== 'h' )) {
lftocrlf = 1;
data = data + 5 ; // we have processed the 5 bytes ESC sequence
data_len = data_len - 5;
}
}
}
@ -2466,8 +2468,18 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
if (c->datagram)
buffer_put_string(&c->output, data, data_len);
else
else {
#ifndef WIN32_FIXME
buffer_append(&c->output, data, data_len);
#else
buffer_append(&c->output, data, data_len);
if ( c->isatty ) {
buffer_append(&c->input, data, data_len); // we echo the data if it is sshd server and pty interactive mode
if ( (data_len ==1) && (data[0] == '\b') )
buffer_append(&c->input, " \b", 2); // for backspace, we need to send space and another backspace for visual erase
}
#endif
}
packet_check_eom();
return 0;
}

View File

@ -2470,6 +2470,38 @@ int WSHELPread(int sfd, char *dst, unsigned int max)
sfd, GetLastError());
}
break;
}
case 99:
{
ret = _getch();
if ( ( ret == 0) || (ret == 0xE0) ) {
dst[0] = ret ;
ret = _getch(); // function key or arrow key needs 2 calls, the first returning a 0 or 0xE0
dst[1] = ret;
ret = 2;
}
else {
dst[0] = ret;
ret = 1;
}
if (FD_ISSET(sfd_to_fd(sfd), &debug_sfds))
{
if (ret > 0)
{
dst[ret] = '\0';
debug("read[%d] len %d: %s", sfd_to_fd(sfd), ret, dst);
}
}
if (ret < 0)
{
error("read from pipe/console sfd [%d] failed with error code [%d]",
sfd, GetLastError());
}
break;
}
}

View File

@ -774,6 +774,21 @@ do_exec_no_pty(Session *s, const char *command)
GetUserName(name, &size);
//if (!(s -> is_subsystem)) {
// Send to the remote client ANSI/VT Sequence so that they send us CRLF in place of LF
//Channel *c=channel_by_id ( s->chanid );
//buffer_append(&c->input, "\033[20h", 5);
//channel_output_poll();
//}
//if (s ->ttyfd != -1) {
// set the channel to tty interactive type
// Channel *c=channel_by_id ( s->chanid );
// c->isatty = 1;
//}
if ( (s->term) && (s->term[0]) )
SetEnvironmentVariable("TERM", s->term);
/*
* Create new process as other user using access token object.
*/
@ -870,7 +885,10 @@ do_exec_no_pty(Session *s, const char *command)
if (compat20)
{
if ( s->ttyfd == -1)
session_set_fds(s, sockin[1], sockout[1], sockerr[1], s -> is_subsystem, 0);
else
session_set_fds(s, sockin[1], sockout[1], sockerr[1], s -> is_subsystem, 1); // tty interctive session
}
else
{

View File

@ -91,10 +91,13 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
#else
/*
* Not implemented on Win32.
* Simple console screen implementation in Win32 to give a Unix like pty for interactive sessions
*/
return 0;
*ttyfd = 0; // first ttyfd & ptyfd is indexed at 0
*ptyfd = 0;
strlcpy(namebuf, "console", namebuflen);
return 1;
//return 0;
#endif
}

View File

@ -505,5 +505,141 @@ set:
/* Set the new modes for the terminal. */
if (tcsetattr(fd, TCSANOW, &tio) == -1)
logit("Setting tty modes failed: %.100s", strerror(errno));
#else
//struct termios tio;
u_int tio[255]; // win32 dummy
u_int tioFIELD ;
int opcode, baud;
int n_bytes = 0;
int failure = 0;
u_int (*get_arg)(void);
int arg_size;
if (compat20) {
*n_bytes_ptr = packet_get_int();
if (*n_bytes_ptr == 0)
return;
get_arg = packet_get_int;
arg_size = 4;
} else {
get_arg = packet_get_char;
arg_size = 1;
}
/*
* Get old attributes for the terminal. We will modify these
* flags. I am hoping that if there are any machine-specific
* modes, they will initially have reasonable values.
*/
//if (tcgetattr(fd, &tio) == -1) {
//logit("tcgetattr: %.100s", strerror(errno));
//failure = -1;
//}
for (;;) {
n_bytes += 1;
opcode = packet_get_char();
switch (opcode) {
case TTY_OP_END:
goto set;
/* XXX: future conflict possible */
case TTY_OP_ISPEED_PROTO1:
case TTY_OP_ISPEED_PROTO2:
n_bytes += 4;
baud = packet_get_int();
break;
/* XXX: future conflict possible */
case TTY_OP_OSPEED_PROTO1:
case TTY_OP_OSPEED_PROTO2:
n_bytes += 4;
baud = packet_get_int();
break;
#define TTYCHAR(NAME, OP) \
case OP: \
n_bytes += arg_size; \
tio[NAME] = special_char_decode(get_arg()); \
break;
#define TTYMODE(NAME, FIELD, OP) \
case OP: \
n_bytes += arg_size; \
if (get_arg()) \
tioFIELD |= NAME; \
else \
tioFIELD &= ~NAME; \
break;
//#include "ttymodes.h"
#undef TTYCHAR
#undef TTYMODE
default:
debug("Ignoring unsupported tty mode opcode %d (0x%x)",
opcode, opcode);
if (!compat20) {
/*
* SSH1:
* Opcodes 1 to 127 are defined to have
* a one-byte argument.
* Opcodes 128 to 159 are defined to have
* an integer argument.
*/
if (opcode > 0 && opcode < 128) {
n_bytes += 1;
(void) packet_get_char();
break;
} else if (opcode >= 128 && opcode < 160) {
n_bytes += 4;
(void) packet_get_int();
break;
} else {
/*
* It is a truly undefined opcode (160 to 255).
* We have no idea about its arguments. So we
* must stop parsing. Note that some data
* may be left in the packet; hopefully there
* is nothing more coming after the mode data.
*/
logit("parse_tty_modes: unknown opcode %d",
opcode);
goto set;
}
} else {
/*
* SSH2:
* Opcodes 1 to 159 are defined to have
* a uint32 argument.
* Opcodes 160 to 255 are undefined and
* cause parsing to stop.
*/
if (opcode > 0 && opcode < 160) {
n_bytes += 4;
(void) packet_get_int();
break;
} else {
logit("parse_tty_modes: unknown opcode %d",
opcode);
goto set;
}
}
}
}
set:
if (*n_bytes_ptr != n_bytes) {
*n_bytes_ptr = n_bytes;
logit("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
*n_bytes_ptr, n_bytes);
return; /* Don't process bytes passed */
}
if (failure == -1)
return; /* Packet parsed ok but tcgetattr() failed */
/* Set the new modes for the terminal. */
//if (tcsetattr(fd, TCSANOW, &tio) == -1)
//logit("Setting tty modes failed: %.100s", strerror(errno));
#endif
}