Skip to content

Commit

Permalink
Merge pull request #614 from JacobBarthelmeh/err
Browse files Browse the repository at this point in the history
send error status on exit
  • Loading branch information
ejohnstown authored Jan 23, 2024
2 parents 406a7fc + ad8bd95 commit dce3cf0
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 19 deletions.
5 changes: 5 additions & 0 deletions apps/wolfssh/wolfssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,11 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args)
}
}
WCLOSESOCKET(sockFd);

#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL)
((func_args*)args)->return_code = wolfSSH_GetExitStatus(ssh);
#endif

wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E)
Expand Down
31 changes: 31 additions & 0 deletions apps/wolfsshd/test/error_return.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

# sshd local test

PWD=`pwd`
cd ../../..

TEST_CLIENT="./examples/client/client"
USER=`whoami`
PRIVATE_KEY="./keys/hansel-key-ecc.der"
PUBLIC_KEY="./keys/hansel-key-ecc.pub"

if [ -z "$1" ] || [ -z "$2" ]; then
echo "expecting host and port as arguments"
echo "./error_return.sh 127.0.0.1 22222"
exit -1
fi

echo "$TEST_CLIENT -c 'bash -c \"(exit 2)\"' -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\""
$TEST_CLIENT -c 'bash -c "(exit 2)"' -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h "$1" -p "$2"
RESULT=$?
if [ "$RESULT" != 2 ]; then
echo "Expecting error return value of 2 for failed ls command, found $RESULT"
cd $PWD
exit 1
fi

cd $PWD
exit 0


4 changes: 4 additions & 0 deletions apps/wolfsshd/test/run_all_sshd_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ run_test() {
run_test "sshd_exec_test.sh"
run_test "sshd_term_size_test.sh"

#Github actions needs resolved for these test cases
#run_test "error_return.sh"
#run_test "sshd_login_grace_test.sh"

# add aditional tests here, check on var USING_LOCAL_HOST if can make sshd
# server start/restart with changes

Expand Down
45 changes: 38 additions & 7 deletions apps/wolfsshd/wolfsshd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,12 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
HeapFree(GetProcessHeap(), 0, ext.lpAttributeList);
}

if (wolfSSH_SetExitStatus(ssh, processState) !=
WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue sending childs exit "
"status");
}

ClosePseudoConsole(pCon);
CloseHandle(processInfo.hThread);
CloseHandle(wolfSSHD_GetAuthToken(conn->auth));
Expand Down Expand Up @@ -1308,13 +1314,9 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue opening shell");
exit(1);
}
exit(0); /* exit child process and close down SSH connection */
exit(ret); /* exit child process and close down SSH connection */
}

/* do not wait for status of child process, and signal that the child can
* be reaped to avoid zombie processes when running in the foreground */
signal(SIGCHLD, SIG_IGN);

if (wolfSSHD_AuthReducePermissionsUser(conn->auth, pPasswd->pw_uid,
pPasswd->pw_gid) != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user ID");
Expand Down Expand Up @@ -1454,6 +1456,27 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
}
}

/* get return value of child process */
{
int waitStatus;

do {
rc = waitpid(childPid, &waitStatus, 0);
/* if the waitpid experinced an interupt then try again */
} while (rc < 0 && errno == EINTR);

if (rc < 0) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue waiting for childs exit "
"status");
}
else {
if (wolfSSH_SetExitStatus(ssh, (word32)WEXITSTATUS(waitStatus)) !=
WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue setting childs exit "
"status");
}
}
}
(void)conn;
return WS_SUCCESS;
}
Expand Down Expand Up @@ -1657,7 +1680,7 @@ static void* HandleConnection(void* arg)
SHELL_Subsystem(conn, ssh, pPasswd, usrConf,
wolfSSH_GetSessionCommand(ssh));
}
#endif /* WOLFSH_SHELL */
#endif /* WOLFSSH_SHELL */

/* SCP can be an exec type */
if (ret == WS_SCP_INIT) {
Expand Down Expand Up @@ -1712,9 +1735,16 @@ static void* HandleConnection(void* arg)
break;
}

if (error != WS_WANT_READ && error != WS_WANT_WRITE) {
if (ret == WS_FATAL_ERROR &&
(error != WS_WANT_READ &&
error != WS_WANT_WRITE)) {
break;
}
#ifdef _WIN32
Sleep(1);
#else
usleep(1);
#endif
}

if (attempt == maxAttempt) {
Expand All @@ -1724,6 +1754,7 @@ static void* HandleConnection(void* arg)
}
}

/* check if there is a response to the shutdown */
wolfSSH_free(ssh);
if (conn != NULL) {
WCLOSESOCKET(conn->fd);
Expand Down
12 changes: 10 additions & 2 deletions examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -982,15 +982,23 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
err_sys("Sending the shutdown messages failed.");
}
ret = wolfSSH_worker(ssh, NULL);
if (ret != WS_SUCCESS) {
if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E &&
ret != WS_CHANNEL_CLOSED) {
err_sys("Failed to listen for close messages from the peer.");
}
}
WCLOSESOCKET(sockFd);

#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL)
((func_args*)args)->return_code = wolfSSH_GetExitStatus(ssh);
#endif

wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E)
if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E &&
ret != WS_CHANNEL_CLOSED) {
err_sys("Closing client stream failed");
}

ClientFreeBuffers(pubKeyName, privKeyName);
#if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS)
Expand Down
34 changes: 34 additions & 0 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -7542,6 +7542,40 @@ static int DoChannelRequest(WOLFSSH* ssh,
}
}
#endif /* WOLFSSH_SHELL && WOLFSSH_TERM */
#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL)
else if (WSTRNCMP(type, "exit-status", typeSz) == 0) {
ret = GetUint32(&ssh->exitStatus, buf, len, &begin);
WLOG(WS_LOG_AGENT, "Got exit status %u.", ssh->exitStatus);
}
else if (WSTRNCMP(type, "exit-signal", typeSz) == 0) {
char sig[WOLFSSH_MAX_NAMESZ];
word32 sigSz;
byte coreDumped;

WLOG(WS_LOG_AGENT, "Got exit signal, remote command terminated");

sigSz = WOLFSSH_MAX_NAMESZ;
ret = GetString(sig, &sigSz, buf, len, &begin);
if (ret == WS_SUCCESS) {
WLOG(WS_LOG_AGENT, "SIGNAL : %s", sig);
ret = GetBoolean(&coreDumped, buf, len, &begin);
}

if (ret == WS_SUCCESS) {
WLOG(WS_LOG_AGENT, "Core Dumped?: %d", coreDumped);
sigSz = WOLFSSH_MAX_NAMESZ;
ret = GetString(sig, &sigSz, buf, len, &begin);
}

if (ret == WS_SUCCESS) {
WLOG(WS_LOG_AGENT, "Error Msg : %s", sig);
sigSz = WOLFSSH_MAX_NAMESZ;

/* getting language tag */
ret = GetString(sig, &sigSz, buf, len, &begin);
}
}
#endif
}

if (ret == WS_SUCCESS)
Expand Down
71 changes: 61 additions & 10 deletions src/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -954,24 +954,47 @@ int wolfSSH_connect(WOLFSSH* ssh)
int wolfSSH_shutdown(WOLFSSH* ssh)
{
int ret = WS_SUCCESS;
WOLFSSH_CHANNEL* channel = NULL;

WLOG(WS_LOG_DEBUG, "Entering wolfSSH_shutdown()");

if (ssh == NULL || ssh->channelList == NULL)
ret = WS_BAD_ARGUMENT;

if (ret == WS_SUCCESS)
ret = SendChannelEof(ssh, ssh->channelList->peerChannel);
/* look up the channel if it still exists */
if (ret == WS_SUCCESS) {
channel = ChannelFind(ssh, ssh->channelList->peerChannel, WS_CHANNEL_ID_SELF);
}

/* continue on success and in case where queing up send packets */
if (ret == WS_SUCCESS ||
(ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE))
ret = SendChannelExit(ssh, ssh->channelList->peerChannel, 0);
/* if channel close was not already sent then send it */
if (channel != NULL && !channel->closeTxd) {
if (ret == WS_SUCCESS) {
ret = SendChannelEof(ssh, ssh->channelList->peerChannel);
}

/* continue on success and in case where queing up send packets */
if (ret == WS_SUCCESS ||
(ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE))
ret = SendChannelClose(ssh, ssh->channelList->peerChannel);
/* continue on success and in case where queing up send packets */
if (ret == WS_SUCCESS ||
(ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE)) {
ret = SendChannelExit(ssh, ssh->channelList->peerChannel,
#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL)
ssh->exitStatus);
#else
0);
#endif
}

/* continue on success and in case where queing up send packets */
if (ret == WS_SUCCESS ||
(ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE))
ret = SendChannelClose(ssh, ssh->channelList->peerChannel);
}


/* if the channel was not yet removed then read to get
* response to SendChannelClose */
if (channel != NULL && ret == WS_SUCCESS) {
ret = wolfSSH_worker(ssh, NULL);
}

if (ssh != NULL && ssh->channelList == NULL) {
WLOG(WS_LOG_DEBUG, "channel list was already removed");
Expand Down Expand Up @@ -1365,6 +1388,34 @@ void wolfSSH_SetTerminalResizeCtx(WOLFSSH* ssh, void* usrCtx)
#endif


#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL)
/* returns the exit status captured from the connection if any */
int wolfSSH_GetExitStatus(WOLFSSH* ssh)
{
if (ssh == NULL) {
WLOG(WS_LOG_DEBUG, "wolfSSH_GetExitStatus WOLFSSH struct was NULL");
return WS_BAD_ARGUMENT;
}
return ssh->exitStatus;
}


/* Sets the exit status to send on shutdown
* returns WS_SUCCESS on success */
int wolfSSH_SetExitStatus(WOLFSSH* ssh, word32 exitStatus)
{
if (ssh == NULL) {
WLOG(WS_LOG_DEBUG, "wolfSSH_SetExitStatus WOLFSSH struct was NULL");
return WS_BAD_ARGUMENT;
}
WLOG(WS_LOG_DEBUG, "wolfSSH_SetExitStatus sending exit status %u",
exitStatus);
ssh->exitStatus = exitStatus;
return WS_SUCCESS;
}
#endif


/* Used to set the channel request type sent in wolfSSH connect. The default
* type set is shell if this function is not called.
*
Expand Down
8 changes: 8 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,14 @@ static void test_wolfSSH_SFTP_SendReadPacket(void)
/* If the socket is closed on shutdown, peer is gone, this is OK. */
argsCount = WS_SUCCESS;
}

#if DEFAULT_HIGHWATER_MARK < 8000
if (argsCount == WS_REKEYING) {
/* in cases where highwater mark is really small a re-key could happen */
argsCount = WS_SUCCESS;
}
#endif

AssertIntEQ(argsCount, WS_SUCCESS);

wolfSSH_free(ssh);
Expand Down
5 changes: 5 additions & 0 deletions wolfssh/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,9 @@ struct WOLFSSH {
byte* modes;
word32 modesSz;
#endif
#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL)
word32 exitStatus;
#endif
};


Expand Down Expand Up @@ -953,6 +956,8 @@ WOLFSSH_LOCAL int SendChannelTerminalResize(WOLFSSH*, word32, word32, word32,
WOLFSSH_LOCAL int SendChannelTerminalRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendChannelAgentRequest(WOLFSSH* ssh);
WOLFSSH_LOCAL int SendChannelSuccess(WOLFSSH*, word32, int);
WOLFSSH_LOCAL int SendChannelExitStatus(WOLFSSH* ssh, word32 channelId,
word32 exitStatus);
WOLFSSH_LOCAL int GenerateKey(byte, byte, byte*, word32, const byte*, word32,
const byte*, word32, const byte*, word32, byte doKeyPad);

Expand Down
2 changes: 2 additions & 0 deletions wolfssh/ssh.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ typedef int (*WS_CallbackTerminalSize)(WOLFSSH*, word32, word32, word32,
WOLFSSH_API void wolfSSH_SetTerminalResizeCb(WOLFSSH* ssh,
WS_CallbackTerminalSize cb);
WOLFSSH_API void wolfSSH_SetTerminalResizeCtx(WOLFSSH* ssh, void* usrCtx);
WOLFSSH_API int wolfSSH_GetExitStatus(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_SetExitStatus(WOLFSSH* ssh, word32 exitStatus);


enum WS_HighwaterSide {
Expand Down

0 comments on commit dce3cf0

Please sign in to comment.