Skip to content

Commit

Permalink
wolfSSHd Terminal
Browse files Browse the repository at this point in the history
1. Set the terminal modes and the window size after the child process is
   running.
2. Decode the modes list from the pty-request message.
3. Store the modes list for later use.
4. Use the correct FD for updating the term settings.
  • Loading branch information
ejohnstown committed Dec 28, 2023
1 parent 60a2960 commit ae88a5e
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 25 deletions.
14 changes: 8 additions & 6 deletions apps/wolfsshd/wolfsshd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
271 changes: 257 additions & 14 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
}
Expand Down
Empty file added sshd_config
Empty file.
14 changes: 9 additions & 5 deletions wolfssh/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
};

Expand Down Expand Up @@ -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 */

Expand Down
1 change: 1 addition & 0 deletions wolfssh/ssh.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit ae88a5e

Please sign in to comment.