diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index de6b14da2..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 */ @@ -1193,6 +1210,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; @@ -1204,6 +1222,12 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, forcedCmd = wolfSSHD_ConfigGetForcedCmd(usrConf); + ptyReq = SHELL_IsPty(ssh); + 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 */ if (forcedCmd == NULL) { @@ -1223,8 +1247,9 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, return WS_FATAL_ERROR; } + /* create pipes for stdout and stderr */ - if (forcedCmd) { + if (!ptyReq || forcedCmd) { if (pipe(stdoutPipe) != 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue creating stdout pipe"); return WS_FATAL_ERROR; @@ -1263,7 +1288,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, signal(SIGINT, SIG_DFL); signal(SIGCHLD, SIG_DFL); - if (forcedCmd) { + if (!ptyReq || forcedCmd) { close(stdoutPipe[0]); close(stderrPipe[0]); close(stdinPipe[1]); @@ -1390,7 +1415,13 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, close(stderrPipe[1]); close(stdinPipe[1]); } - else { + else if (!ptyReq) { + 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 +1474,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #endif wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd); - if (forcedCmd) { + if (!ptyReq || forcedCmd) { close(stdoutPipe[1]); close(stderrPipe[1]); close(stdinPipe[0]); @@ -1469,7 +1500,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 || forcedCmd) { FD_SET(stdoutPipe[0], &readFds); if (stdoutPipe[0] > maxFd) maxFd = stdoutPipe[0]; @@ -1515,7 +1546,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (cnt_r <= 0) break; - if (forcedCmd) { + if (!ptyReq || forcedCmd) { cnt_w = (int)write(stdinPipe[1], channelBuffer, cnt_r); } @@ -1555,7 +1586,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 || forcedCmd)) { /* SSH is done, close stdin pipe to child process */ close(stdinPipe[1]); stdinPipe[1] = -1; @@ -1585,7 +1616,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } - if (forcedCmd) { + if (!ptyReq || forcedCmd) { if (FD_ISSET(stderrPipe[0], &readFds)) { cnt_r = (int)read(stderrPipe[0], shellBuffer, sizeof shellBuffer); @@ -1725,7 +1756,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 || 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..05005b64a 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; + 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 f98fb3020..3423dec18 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -3233,6 +3233,18 @@ 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(const WOLFSSH_CHANNEL* channel) +{ + if (channel == NULL) { + return WS_BAD_ARGUMENT; + } + return channel->ptyReq; +} +#endif + + const char* wolfSSH_ChannelGetSessionCommand(const WOLFSSH_CHANNEL* channel) { const char* cmd = NULL; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 261ae6d42..b7f28045e 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -933,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 ccdfda476..94b391f55 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_ChannelIsPty(const WOLFSSH_CHANNEL* channel); /* Channel callbacks */ typedef int (*WS_CallbackChannelOpen)(WOLFSSH_CHANNEL* channel, void* ctx);