From 6fe09bdb35ac5ceac67ca59eb71ed933030f186a Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Tue, 16 Sep 2025 10:11:46 -0600 Subject: [PATCH 1/3] do not treat shell as interactive until pty-req received --- apps/wolfsshd/wolfsshd.c | 27 ++++++++++++++++++--------- src/internal.c | 1 + src/ssh.c | 19 +++++++++++++++++++ wolfssh/internal.h | 1 + wolfssh/ssh.h | 1 + 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index de6b14da2..bb7598423 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1193,6 +1193,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, int wantWrite = 0; int peerConnected = 1; int stdoutEmpty = 0; + int ptyReq = 0; childFd = -1; stdoutPipe[0] = -1; @@ -1203,6 +1204,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, stdinPipe[1] = -1; forcedCmd = wolfSSHD_ConfigGetForcedCmd(usrConf); + ptyReq = wolfSSH_ReceivedPtyReq(ssh); /* do not overwrite a forced command with 'exec' sub shell. Only set the * 'exec' command when no forced command is set */ @@ -1223,8 +1225,9 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, return WS_FATAL_ERROR; } + /* create pipes for stdout and stderr */ - if (forcedCmd) { + if (ptyReq == 0 || forcedCmd) { if (pipe(stdoutPipe) != 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue creating stdout pipe"); return WS_FATAL_ERROR; @@ -1263,7 +1266,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, signal(SIGINT, SIG_DFL); signal(SIGCHLD, SIG_DFL); - if (forcedCmd) { + if (ptyReq == 0 || forcedCmd) { close(stdoutPipe[0]); close(stderrPipe[0]); close(stdinPipe[1]); @@ -1390,7 +1393,13 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, close(stderrPipe[1]); close(stdinPipe[1]); } - else { + else if (ptyReq == 0) { + ret = execv(cmd, (char**)args); + close(stdoutPipe[1]); + close(stderrPipe[1]); + close(stdinPipe[1]); + } + else { /* open interactive shell */ ret = execv(cmd, (char**)args); } if (ret && errno) { @@ -1443,7 +1452,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #endif wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd); - if (forcedCmd) { + if (ptyReq == 0 || forcedCmd) { close(stdoutPipe[1]); close(stderrPipe[1]); close(stdinPipe[0]); @@ -1469,7 +1478,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) { /* select on stdout/stderr pipes with forced commands */ - if (forcedCmd) { + if (ptyReq == 0 || forcedCmd) { FD_SET(stdoutPipe[0], &readFds); if (stdoutPipe[0] > maxFd) maxFd = stdoutPipe[0]; @@ -1515,7 +1524,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (cnt_r <= 0) break; - if (forcedCmd) { + if (ptyReq == 0 || forcedCmd) { cnt_w = (int)write(stdinPipe[1], channelBuffer, cnt_r); } @@ -1555,7 +1564,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, current = wolfSSH_ChannelFind(ssh, lastChannel, WS_CHANNEL_ID_SELF); eof = wolfSSH_ChannelGetEof(current); - if (eof && forcedCmd) { + if (eof && (ptyReq == 0 || forcedCmd)) { /* SSH is done, close stdin pipe to child process */ close(stdinPipe[1]); stdinPipe[1] = -1; @@ -1585,7 +1594,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } - if (forcedCmd) { + if (ptyReq == 0 || forcedCmd) { if (FD_ISSET(stderrPipe[0], &readFds)) { cnt_r = (int)read(stderrPipe[0], shellBuffer, sizeof shellBuffer); @@ -1725,7 +1734,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } /* check for any left over data in pipes then close them */ - if (forcedCmd) { + if (ptyReq == 0 || forcedCmd) { int readSz; fcntl(stdoutPipe[0], F_SETFL, fcntl(stdoutPipe[0], F_GETFL) diff --git a/src/internal.c b/src/internal.c index 63f0e1af7..9c98e42b5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8951,6 +8951,7 @@ static int DoChannelRequest(WOLFSSH* ssh, word32 termSz, modesSz = 0; word32 widthChar, heightRows, widthPixels, heightPixels; + ssh->ptyReq = 1; /* recieved a pty request */ termSz = (word32)sizeof(term); ret = GetString(term, &termSz, buf, len, &begin); if (ret == WS_SUCCESS) diff --git a/src/ssh.c b/src/ssh.c index f98fb3020..777247c4a 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -2539,6 +2539,25 @@ WS_SessionType wolfSSH_GetSessionType(const WOLFSSH* ssh) } +#if defined(WOLFSSH_TERM) +int wolfSSH_ReceivedPtyReq(const WOLFSSH* ssh) +{ + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ReceivedPtyReq"); + + if (ssh == NULL) { + return WS_BAD_ARGUMENT; + } + + if (ssh->ptyReq) { + return 1; + } + else { + return 0; + } +} +#endif + + const char* wolfSSH_GetSessionCommand(const WOLFSSH* ssh) { WLOG(WS_LOG_DEBUG, "Entering wolfSSH_GetSessionCommand()"); diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 261ae6d42..52175c68e 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -913,6 +913,7 @@ struct WOLFSSH { word32 heightPixels; /* pixel height */ byte* modes; word32 modesSz; + byte ptyReq:1; /* flag for if interactive pty request was received */ #endif #if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL) word32 exitStatus; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index ccdfda476..6ce71b5a8 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -233,6 +233,7 @@ WOLFSSH_API WS_SessionType wolfSSH_ChannelGetSessionType( const WOLFSSH_CHANNEL* channel); WOLFSSH_API const char* wolfSSH_ChannelGetSessionCommand( const WOLFSSH_CHANNEL* channel); +WOLFSSH_API int wolfSSH_ReceivedPtyReq(const WOLFSSH* ssh); /* Channel callbacks */ typedef int (*WS_CallbackChannelOpen)(WOLFSSH_CHANNEL* channel, void* ctx); From 7c9f8f1758ee634582a00d9d56ac34f31d8db42f Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Wed, 17 Sep 2025 14:03:05 -0600 Subject: [PATCH 2/3] refactor pty flag to Channel level and treat result as boolean in wolfsshd checks --- apps/wolfsshd/wolfsshd.c | 25 +++++++++++++--------- src/internal.c | 2 +- src/ssh.c | 46 +++++++++++++++++++++++----------------- wolfssh/internal.h | 2 +- wolfssh/ssh.h | 2 +- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index bb7598423..d1ce8302d 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1204,7 +1204,12 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, stdinPipe[1] = -1; forcedCmd = wolfSSHD_ConfigGetForcedCmd(usrConf); - ptyReq = wolfSSH_ReceivedPtyReq(ssh); + + ptyReq = wolfSSH_ChannelIsPty(ssh, NULL); + if (ptyReq < 0) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure get channel PTY state"); + return WS_FATAL_ERROR; + } /* do not overwrite a forced command with 'exec' sub shell. Only set the * 'exec' command when no forced command is set */ @@ -1227,7 +1232,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, /* create pipes for stdout and stderr */ - if (ptyReq == 0 || forcedCmd) { + if (!ptyReq || forcedCmd) { if (pipe(stdoutPipe) != 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue creating stdout pipe"); return WS_FATAL_ERROR; @@ -1266,7 +1271,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, signal(SIGINT, SIG_DFL); signal(SIGCHLD, SIG_DFL); - if (ptyReq == 0 || forcedCmd) { + if (!ptyReq || forcedCmd) { close(stdoutPipe[0]); close(stderrPipe[0]); close(stdinPipe[1]); @@ -1393,7 +1398,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, close(stderrPipe[1]); close(stdinPipe[1]); } - else if (ptyReq == 0) { + else if (!ptyReq) { ret = execv(cmd, (char**)args); close(stdoutPipe[1]); close(stderrPipe[1]); @@ -1452,7 +1457,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #endif wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd); - if (ptyReq == 0 || forcedCmd) { + if (!ptyReq || forcedCmd) { close(stdoutPipe[1]); close(stderrPipe[1]); close(stdinPipe[0]); @@ -1478,7 +1483,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) { /* select on stdout/stderr pipes with forced commands */ - if (ptyReq == 0 || forcedCmd) { + if (!ptyReq || forcedCmd) { FD_SET(stdoutPipe[0], &readFds); if (stdoutPipe[0] > maxFd) maxFd = stdoutPipe[0]; @@ -1524,7 +1529,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (cnt_r <= 0) break; - if (ptyReq == 0 || forcedCmd) { + if (!ptyReq || forcedCmd) { cnt_w = (int)write(stdinPipe[1], channelBuffer, cnt_r); } @@ -1564,7 +1569,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, current = wolfSSH_ChannelFind(ssh, lastChannel, WS_CHANNEL_ID_SELF); eof = wolfSSH_ChannelGetEof(current); - if (eof && (ptyReq == 0 || forcedCmd)) { + if (eof && (!ptyReq || forcedCmd)) { /* SSH is done, close stdin pipe to child process */ close(stdinPipe[1]); stdinPipe[1] = -1; @@ -1594,7 +1599,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } - if (ptyReq == 0 || forcedCmd) { + if (!ptyReq || forcedCmd) { if (FD_ISSET(stderrPipe[0], &readFds)) { cnt_r = (int)read(stderrPipe[0], shellBuffer, sizeof shellBuffer); @@ -1734,7 +1739,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } /* check for any left over data in pipes then close them */ - if (ptyReq == 0 || forcedCmd) { + if (!ptyReq || forcedCmd) { int readSz; fcntl(stdoutPipe[0], F_SETFL, fcntl(stdoutPipe[0], F_GETFL) diff --git a/src/internal.c b/src/internal.c index 9c98e42b5..05005b64a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8951,7 +8951,7 @@ static int DoChannelRequest(WOLFSSH* ssh, word32 termSz, modesSz = 0; word32 widthChar, heightRows, widthPixels, heightPixels; - ssh->ptyReq = 1; /* recieved a pty request */ + channel->ptyReq = 1; /* recieved a pty request */ termSz = (word32)sizeof(term); ret = GetString(term, &termSz, buf, len, &begin); if (ret == WS_SUCCESS) diff --git a/src/ssh.c b/src/ssh.c index 777247c4a..f3bc1bf5c 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -2539,25 +2539,6 @@ WS_SessionType wolfSSH_GetSessionType(const WOLFSSH* ssh) } -#if defined(WOLFSSH_TERM) -int wolfSSH_ReceivedPtyReq(const WOLFSSH* ssh) -{ - WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ReceivedPtyReq"); - - if (ssh == NULL) { - return WS_BAD_ARGUMENT; - } - - if (ssh->ptyReq) { - return 1; - } - else { - return 0; - } -} -#endif - - const char* wolfSSH_GetSessionCommand(const WOLFSSH* ssh) { WLOG(WS_LOG_DEBUG, "Entering wolfSSH_GetSessionCommand()"); @@ -3252,6 +3233,33 @@ WS_SessionType wolfSSH_ChannelGetSessionType(const WOLFSSH_CHANNEL* channel) } +#if defined(WOLFSSH_TERM) +/* returns 1 if a PTY was requested, 0 if not, and negative on failure */ +int wolfSSH_ChannelIsPty(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) +{ + WOLFSSH_CHANNEL* channelPtr; + int ret = WS_SUCCESS; + + channelPtr = channel; + + /* if channel is NULL than use the last rxtx channel */ + if (channelPtr == NULL) { + word32 channelId = 0; + + ret = wolfSSH_GetLastRxId(ssh, &channelId); + if (ret == WS_SUCCESS) { + channelPtr = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); + } + } + + if (ret == WS_SUCCESS) { + ret = channelPtr->ptyReq; + } + return ret; +} +#endif + + const char* wolfSSH_ChannelGetSessionCommand(const WOLFSSH_CHANNEL* channel) { const char* cmd = NULL; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 52175c68e..b7f28045e 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -913,7 +913,6 @@ struct WOLFSSH { word32 heightPixels; /* pixel height */ byte* modes; word32 modesSz; - byte ptyReq:1; /* flag for if interactive pty request was received */ #endif #if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL) word32 exitStatus; @@ -934,6 +933,7 @@ struct WOLFSSH_CHANNEL { byte eofRxd : 1; byte eofTxd : 1; byte openConfirmed : 1; + byte ptyReq : 1; /* flag for if interactive pty request was received */ word32 channel; word32 windowSz; word32 maxPacketSz; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 6ce71b5a8..70290908e 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -233,7 +233,7 @@ WOLFSSH_API WS_SessionType wolfSSH_ChannelGetSessionType( const WOLFSSH_CHANNEL* channel); WOLFSSH_API const char* wolfSSH_ChannelGetSessionCommand( const WOLFSSH_CHANNEL* channel); -WOLFSSH_API int wolfSSH_ReceivedPtyReq(const WOLFSSH* ssh); +WOLFSSH_API int wolfSSH_ChannelIsPty(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel); /* Channel callbacks */ typedef int (*WS_CallbackChannelOpen)(WOLFSSH_CHANNEL* channel, void* ctx); From 91c9279c2228bf33fcbf061926115e1b41c5678b Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Wed, 17 Sep 2025 15:13:23 -0600 Subject: [PATCH 3/3] simplify wolfSSH_ChannelIsPty to only take a pointer to a channel --- apps/wolfsshd/wolfsshd.c | 19 ++++++++++++++++++- src/ssh.c | 23 ++++------------------- wolfssh/ssh.h | 2 +- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index d1ce8302d..d2bb08ab6 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1164,6 +1164,23 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #include #endif +static int SHELL_IsPty(WOLFSSH* ssh) +{ + WOLFSSH_CHANNEL* channel; + int ret = WS_SUCCESS; + word32 channelId = 0; + + ret = wolfSSH_GetLastRxId(ssh, &channelId); + if (ret == WS_SUCCESS) { + channel = wolfSSH_ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); + } + + if (ret == WS_SUCCESS) { + ret = wolfSSH_ChannelIsPty(channel); + } + return ret; +} + /* handles creating a new shell env. and maintains SSH connection for incoming * user input as well as output of the shell. * return WS_SUCCESS on success */ @@ -1205,7 +1222,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, forcedCmd = wolfSSHD_ConfigGetForcedCmd(usrConf); - ptyReq = wolfSSH_ChannelIsPty(ssh, NULL); + ptyReq = SHELL_IsPty(ssh); if (ptyReq < 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure get channel PTY state"); return WS_FATAL_ERROR; diff --git a/src/ssh.c b/src/ssh.c index f3bc1bf5c..3423dec18 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -3235,27 +3235,12 @@ WS_SessionType wolfSSH_ChannelGetSessionType(const WOLFSSH_CHANNEL* channel) #if defined(WOLFSSH_TERM) /* returns 1 if a PTY was requested, 0 if not, and negative on failure */ -int wolfSSH_ChannelIsPty(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) +int wolfSSH_ChannelIsPty(const WOLFSSH_CHANNEL* channel) { - WOLFSSH_CHANNEL* channelPtr; - int ret = WS_SUCCESS; - - channelPtr = channel; - - /* if channel is NULL than use the last rxtx channel */ - if (channelPtr == NULL) { - word32 channelId = 0; - - ret = wolfSSH_GetLastRxId(ssh, &channelId); - if (ret == WS_SUCCESS) { - channelPtr = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); - } - } - - if (ret == WS_SUCCESS) { - ret = channelPtr->ptyReq; + if (channel == NULL) { + return WS_BAD_ARGUMENT; } - return ret; + return channel->ptyReq; } #endif diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 70290908e..94b391f55 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -233,7 +233,7 @@ WOLFSSH_API WS_SessionType wolfSSH_ChannelGetSessionType( const WOLFSSH_CHANNEL* channel); WOLFSSH_API const char* wolfSSH_ChannelGetSessionCommand( const WOLFSSH_CHANNEL* channel); -WOLFSSH_API int wolfSSH_ChannelIsPty(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel); +WOLFSSH_API int wolfSSH_ChannelIsPty(const WOLFSSH_CHANNEL* channel); /* Channel callbacks */ typedef int (*WS_CallbackChannelOpen)(WOLFSSH_CHANNEL* channel, void* ctx);