wolfSSHd Terminal

1. Rename the stashed window size values.
2. Set the terminal modes after the child process is running.
3. Decode the modes list from the pty-request message.
4. Store the modes list for later use.
pull/640/head
John Safranek 2023-12-28 14:29:02 -08:00
parent 60a29602e5
commit 711fee25f2
No known key found for this signature in database
GPG Key ID: 8CE817DE0D3CCB4A
5 changed files with 275 additions and 25 deletions

View File

@ -1323,19 +1323,21 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
/* set initial size of terminal based on saved size */
#if defined(HAVE_SYS_IOCTL_H)
wolfSSH_DoModes(ssh->modes, ssh->modesSz, childFd);
{
struct winsize s;
struct winsize s = {0};
s.ws_col = ssh->widthChar;
s.ws_row = ssh->heightRows;
s.ws_xpixel = ssh->widthPixels;
s.ws_ypixel = ssh->heightPixels;
WMEMSET(&s, 0, sizeof s);
s.ws_col = ssh->curX;
s.ws_row = ssh->curY;
s.ws_xpixel = ssh->curXP;
s.ws_ypixel = ssh->curYP;
ioctl(childFd, TIOCSWINSZ, &s);
}
#endif
wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd);
while (ChildRunning) {
byte tmp[2];
fd_set readFds;

View File

@ -7132,6 +7132,243 @@ static int DoChannelClose(WOLFSSH* ssh,
}
#define TTY_SET_CHAR(x,y,z) (x)[(y)] = (byte)(z)
#define TTY_SET_FLAG(x,y,z) (x) = (z) ? ((x) | (y)) : ((x) & ~(y))
int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd)
{
WOLFSSH_TERMIOS term;
word32 idx = 0, arg;
if (!modes || !modesSz || (modesSz % TERMINAL_MODE_SZ > 1))
return -1;
/*
* Modes is a list of opcode-argument pairs. The opcodes are
* bytes and the arguments are uint32s. TTY_OP_END is an opcode
* that terminates the list. Of course, it isn't clear if
* TTY_OP_END has an arguement or note. The RFC doesn't say,
* but in operation it usually doesn't. Allow for an odd single
* byte left over.
*/
tcgetattr(fd, &term);
while (idx < modesSz && modes[idx] != WOLFSSH_TTY_OP_END
&& modes[idx] < WOLFSSH_TTY_INVALID) {
ato32(modes + idx + 1, &arg);
switch (modes[idx]) {
/* Special Control Characters (c_cc) */
case WOLFSSH_VINTR:
TTY_SET_CHAR(term.c_cc, VINTR, arg);
break;
case WOLFSSH_VQUIT:
TTY_SET_CHAR(term.c_cc, VQUIT, arg);
break;
case WOLFSSH_VERASE:
TTY_SET_CHAR(term.c_cc, VERASE, arg);
break;
case WOLFSSH_VKILL:
TTY_SET_CHAR(term.c_cc, VKILL, arg);
break;
case WOLFSSH_VEOF:
TTY_SET_CHAR(term.c_cc, VEOF, arg);
break;
case WOLFSSH_VEOL:
TTY_SET_CHAR(term.c_cc, VEOL, arg);
break;
case WOLFSSH_VEOL2:
TTY_SET_CHAR(term.c_cc, VEOL2, arg);
break;
case WOLFSSH_VSTART:
TTY_SET_CHAR(term.c_cc, VSTART, arg);
break;
case WOLFSSH_VSTOP:
TTY_SET_CHAR(term.c_cc, VSTOP, arg);
break;
case WOLFSSH_VSUSP:
TTY_SET_CHAR(term.c_cc, VSUSP, arg);
break;
case WOLFSSH_VDSUSP:
#ifdef VDSUSP
TTY_SET_CHAR(term.c_cc, VDSUSP, arg);
#endif
break;
case WOLFSSH_VREPRINT:
TTY_SET_CHAR(term.c_cc, VREPRINT, arg);
break;
case WOLFSSH_VWERASE:
TTY_SET_CHAR(term.c_cc, VWERASE, arg);
break;
case WOLFSSH_VLNEXT:
TTY_SET_CHAR(term.c_cc, VLNEXT, arg);
break;
case WOLFSSH_VFLUSH:
#ifdef VFLUSH
TTY_SET_CHAR(term.c_cc, VFLUSH, arg);
#endif
break;
case WOLFSSH_VSWTCH:
#ifdef VSWTCH
TTY_SET_CHAR(term.c_cc, VSWTCH, arg);
#endif
break;
case WOLFSSH_VSTATUS:
#ifdef VSTATUS
TTY_SET_CHAR(term.c_cc, VSTATUS, arg);
#endif
break;
case WOLFSSH_VDISCARD:
TTY_SET_CHAR(term.c_cc, VDISCARD, arg);
break;
/* Input Modes (c_iflag) */
case WOLFSSH_IGNPAR:
TTY_SET_FLAG(term.c_iflag, IGNPAR, arg);
break;
case WOLFSSH_PARMRK:
TTY_SET_FLAG(term.c_iflag, PARMRK, arg);
break;
case WOLFSSH_INPCK:
TTY_SET_FLAG(term.c_iflag, INPCK, arg);
break;
case WOLFSSH_ISTRIP:
TTY_SET_FLAG(term.c_iflag, ISTRIP, arg);
break;
case WOLFSSH_INLCR:
TTY_SET_FLAG(term.c_iflag, INLCR, arg);
break;
case WOLFSSH_IGNCR:
TTY_SET_FLAG(term.c_iflag, IGNCR, arg);
break;
case WOLFSSH_ICRNL:
TTY_SET_FLAG(term.c_iflag, ICRNL, arg);
break;
case WOLFSSH_IUCLC:
#ifdef IUCLC
TTY_SET_FLAG(term.c_iflag, IUCLC, arg);
#endif
break;
case WOLFSSH_IXON:
TTY_SET_FLAG(term.c_iflag, IXON, arg);
break;
case WOLFSSH_IXANY:
TTY_SET_FLAG(term.c_iflag, IXANY, arg);
break;
case WOLFSSH_IXOFF:
TTY_SET_FLAG(term.c_iflag, IXOFF, arg);
break;
case WOLFSSH_IMAXBEL:
TTY_SET_FLAG(term.c_iflag, IMAXBEL, arg);
break;
case WOLFSSH_IUTF8:
#ifdef IUTF8
TTY_SET_FLAG(term.c_iflag, IUTF8, arg);
#endif
break;
/* Local Modes (c_lflag) */
case WOLFSSH_ISIG:
TTY_SET_FLAG(term.c_lflag, ISIG, arg);
break;
case WOLFSSH_ICANON:
TTY_SET_FLAG(term.c_lflag, ICANON, arg);
break;
case WOLFSSH_XCASE:
#ifdef XCASE
TTY_SET_FLAG(term.c_lflag, XCASE, arg);
#endif
break;
case WOLFSSH_ECHO:
TTY_SET_FLAG(term.c_lflag, ECHO, arg);
break;
case WOLFSSH_ECHOE:
TTY_SET_FLAG(term.c_lflag, ECHOE, arg);
break;
case WOLFSSH_ECHOK:
TTY_SET_FLAG(term.c_lflag, ECHOK, arg);
break;
case WOLFSSH_ECHONL:
TTY_SET_FLAG(term.c_lflag, ECHONL, arg);
break;
case WOLFSSH_NOFLSH:
TTY_SET_FLAG(term.c_lflag, NOFLSH, arg);
break;
case WOLFSSH_TOSTOP:
TTY_SET_FLAG(term.c_lflag, TOSTOP, arg);
break;
case WOLFSSH_IEXTEN:
TTY_SET_FLAG(term.c_lflag, IEXTEN, arg);
break;
case WOLFSSH_ECHOCTL:
TTY_SET_FLAG(term.c_lflag, ECHOCTL, arg);
break;
case WOLFSSH_ECHOKE:
TTY_SET_FLAG(term.c_lflag, ECHOKE, arg);
break;
case WOLFSSH_PENDIN:
#ifdef PENDIN
TTY_SET_FLAG(term.c_lflag, PENDIN, arg);
#endif
break;
/* Output Modes (c_oflag) */
case WOLFSSH_OPOST:
TTY_SET_FLAG(term.c_lflag, OPOST, arg);
break;
case WOLFSSH_OLCUC:
#ifdef OLCUC
TTY_SET_FLAG(term.c_lflag, OLCUC, arg);
#endif
break;
case WOLFSSH_ONLCR:
TTY_SET_FLAG(term.c_lflag, ONLCR, arg);
break;
case WOLFSSH_OCRNL:
TTY_SET_FLAG(term.c_lflag, OCRNL, arg);
break;
case WOLFSSH_ONOCR:
TTY_SET_FLAG(term.c_lflag, ONOCR, arg);
break;
case WOLFSSH_ONLRET:
TTY_SET_FLAG(term.c_lflag, ONLRET, arg);
break;
/* Control Modes (c_cflag) */
case WOLFSSH_CS7:
TTY_SET_FLAG(term.c_cflag, CS7, arg);
break;
case WOLFSSH_CS8:
TTY_SET_FLAG(term.c_cflag, CS8, arg);
break;
case WOLFSSH_PARENB:
TTY_SET_FLAG(term.c_cflag, PARENB, arg);
break;
case WOLFSSH_PARODD:
TTY_SET_FLAG(term.c_cflag, PARODD, arg);
break;
/* Baud Rates */
case WOLFSSH_TTY_OP_ISPEED:
cfsetispeed(&term, (speed_t)arg);
break;
case WOLFSSH_TTY_OP_OSPEED:
cfsetospeed(&term, (speed_t)arg);
break;
default:
break;
}
idx += TERMINAL_MODE_SZ;
}
tcsetattr(fd, TCSANOW, &term);
return 0;
}
static int DoChannelRequest(WOLFSSH* ssh,
byte* buf, word32 len, word32* idx)
{
@ -7189,24 +7426,27 @@ static int DoChannelRequest(WOLFSSH* ssh,
ret = GetUint32(&heightPixels, buf, len, &begin);
if (ret == WS_SUCCESS)
ret = GetStringRef(&modesSz, &modes, buf, len, &begin);
WOLFSSH_UNUSED(modes);
WOLFSSH_UNUSED(modesSz);
if (ret == WS_SUCCESS) {
ssh->modes = (byte*)WMALLOC(modesSz, ssh->ctx->heap, 0);
if (ssh->modes == NULL)
ret = WS_MEMORY_E;
}
if (ret == WS_SUCCESS) {
ssh->modesSz = modesSz;
WMEMCPY(ssh->modes, modes, modesSz);
WLOG(WS_LOG_DEBUG, " term = %s", term);
WLOG(WS_LOG_DEBUG, " widthChar = %u", widthChar);
WLOG(WS_LOG_DEBUG, " heightRows = %u", heightRows);
WLOG(WS_LOG_DEBUG, " widthPixels = %u", widthPixels);
WLOG(WS_LOG_DEBUG, " heightPixels = %u", heightPixels);
ssh->curX = widthChar;
ssh->curY = heightRows;
ssh->curXP = widthPixels;
ssh->curYP = heightPixels;
ssh->widthChar = widthChar;
ssh->heightRows = heightRows;
ssh->widthPixels = widthPixels;
ssh->heightPixels = heightPixels;
if (ssh->termResizeCb) {
if (ssh->termResizeCb(ssh, widthChar, heightRows,
widthPixels, heightPixels, ssh->termCtx)
!= WS_SUCCESS) {
widthPixels, heightPixels,
ssh->termCtx) != WS_SUCCESS) {
ret = WS_FATAL_ERROR;
}
}
@ -7276,11 +7516,14 @@ static int DoChannelRequest(WOLFSSH* ssh,
WLOG(WS_LOG_DEBUG, " heightRows = %u", heightRows);
WLOG(WS_LOG_DEBUG, " widthPixels = %u", widthPixels);
WLOG(WS_LOG_DEBUG, " heightPixels = %u", heightPixels);
ssh->curX = widthChar;
ssh->curY = heightRows;
ssh->widthChar = widthChar;
ssh->heightRows = heightRows;
ssh->widthPixels = widthPixels;
ssh->heightPixels = heightPixels;
if (ssh->termResizeCb) {
if (ssh->termResizeCb(ssh, widthChar, heightRows, widthPixels,
heightPixels, ssh->termCtx) != WS_SUCCESS) {
if (ssh->termResizeCb(ssh, widthChar, heightRows,
widthPixels, heightPixels,
ssh->termCtx) != WS_SUCCESS) {
ret = WS_FATAL_ERROR;
}
}

0
sshd_config 100644
View File

View File

@ -378,6 +378,7 @@ enum {
#define UINT32_SZ 4
#define LENGTH_SZ UINT32_SZ
#define SSH_PROTO_SZ 7 /* "SSH-2.0" */
#define TERMINAL_MODE_SZ 5 /* opcode byte + argument uint32 */
#define AEAD_IMP_IV_SZ 4
#define AEAD_EXP_IV_SZ 8
#define AEAD_NONCE_SZ (AEAD_IMP_IV_SZ+AEAD_EXP_IV_SZ)
@ -814,10 +815,12 @@ struct WOLFSSH {
#ifdef WOLFSSH_TERM
WS_CallbackTerminalSize termResizeCb;
void* termCtx;
word32 curX; /* current terminal width */
word32 curY; /* current terminal height */
word32 curXP; /* pixel width */
word32 curYP; /* pixel height */
word32 widthChar; /* current terminal width */
word32 heightRows; /* current terminal height */
word32 widthPixels; /* pixel width */
word32 heightPixels; /* pixel height */
byte* modes;
word32 modesSz;
#endif
};
@ -1262,7 +1265,8 @@ enum TerminalModes {
WOLFSSH_PARENB,
WOLFSSH_PARODD,
WOLFSSH_TTY_OP_ISPEED = 128,
WOLFSSH_TTY_OP_OSPEED
WOLFSSH_TTY_OP_OSPEED,
WOLFSSH_TTY_INVALID = 160
};
#endif /* WOLFSSH_TERM */

View File

@ -282,6 +282,7 @@ typedef enum {
WOLFSSH_SESSION_TERMINAL,
} WS_SessionType;
WOLFSSH_API int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd);
WOLFSSH_API WS_SessionType wolfSSH_GetSessionType(const WOLFSSH*);
WOLFSSH_API const char* wolfSSH_GetSessionCommand(const WOLFSSH*);
WOLFSSH_API int wolfSSH_SetChannelType(WOLFSSH*, byte, byte*, word32);