Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing Channels #674

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 136 additions & 94 deletions apps/wolfsshd/wolfsshd.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,15 @@ static const char defaultBanner[] = "wolfSSHD\n";
typedef struct WOLFSSHD_CONNECTION {
WOLFSSH_CTX* ctx;
WOLFSSHD_AUTH* auth;
WOLFSSH_CHANNEL* channel;
int fd;
int listenFd;
char ip[INET_ADDRSTRLEN];
byte isThreaded;
byte isThreaded:1;
byte doShell:1;
byte doSftp:1;
byte doScp:1;
byte doExec:1;
} WOLFSSHD_CONNECTION;

#ifdef __unix__
Expand Down Expand Up @@ -173,6 +178,50 @@ static void ServiceDebugCb(enum wolfSSH_LogLevel level, const char* const msgStr
}
#endif

static int wsChannelReqCb(WOLFSSH_CHANNEL* channel, void* vCtx)
{
WOLFSSHD_CONNECTION* ctx;
const char* cmd;
WS_SessionType type;

if (!vCtx || !channel) {
return 0;
}

ctx = (WOLFSSHD_CONNECTION*)vCtx;
cmd = wolfSSH_ChannelGetSessionCommand(channel);
type = wolfSSH_ChannelGetSessionType(channel);

#ifdef WOLFSSH_SHELL
if (type == WOLFSSH_SESSION_SHELL) {
ctx->channel = channel;
ctx->doShell = 1;
return 0;
}
#endif
#ifdef WOLFSSH_SCP
if (type == WOLFSSH_SESSION_EXEC) {
ctx->channel = channel;
ctx->doExec = 1;
ctx->doScp = WSTRSTR(cmd, "scp") != NULL;
return 0;
}
#endif
#ifdef WOLFSSH_SFTP
if (type == WOLFSSH_SESSION_SUBSYSTEM) {
if (!WSTRCMP(cmd, "sftp")) {
ctx->channel = channel;
ctx->doSftp = 1;
return 0;
}
}
#endif

wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Unknown or build not supporting session type found");
return 1;
}

static void ShowUsage(void)
{
printf("wolfsshd %s\n", LIBWOLFSSH_VERSION_STRING);
Expand Down Expand Up @@ -311,6 +360,13 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
wolfSSH_CTX_SetBanner(*ctx, banner);
}

/* set the channel request callbacks */
if (ret == WS_SUCCESS) {
wolfSSH_CTX_SetChannelReqShellCb(*ctx, wsChannelReqCb);
wolfSSH_CTX_SetChannelReqExecCb(*ctx, wsChannelReqCb);
wolfSSH_CTX_SetChannelReqSubsysCb(*ctx, wsChannelReqCb);
}

/* Load in host private key */
if (ret == WS_SUCCESS) {

Expand Down Expand Up @@ -541,23 +597,24 @@ static int SCP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
#endif

if (ret == WS_SUCCESS) {
ret = wolfSSH_accept(ssh);
ret = wolfSSH_SCP_DoRequest(ssh);
error = wolfSSH_get_error(ssh);
while (ret != WS_SUCCESS && ret != WS_SCP_COMPLETE
while (ret != WS_SUCCESS
&& ret != WS_SCP_COMPLETE
&& (error == WS_WANT_READ || error == WS_WANT_WRITE)) {

select_ret = tcp_select(conn->fd, 1);
if (select_ret == WS_SELECT_RECV_READY ||
select_ret == WS_SELECT_ERROR_READY ||
error == WS_WANT_WRITE)
{
ret = wolfSSH_accept(ssh);
if (select_ret == WS_SELECT_RECV_READY
|| select_ret == WS_SELECT_ERROR_READY
|| error == WS_WANT_WRITE) {
ret = wolfSSH_SCP_DoRequest(ssh);
error = wolfSSH_get_error(ssh);
}
else if (select_ret == WS_SELECT_TIMEOUT)
else if (select_ret == WS_SELECT_TIMEOUT) {
error = WS_WANT_READ;
else
}
else {
error = WS_FATAL_ERROR;
}
}
}

Expand All @@ -567,7 +624,6 @@ static int SCP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
conn->ip);
}

(void)conn;
#ifdef _WIN32
/* stop impersonating the user */
RevertToSelf();
Expand Down Expand Up @@ -760,6 +816,9 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
if (error == WS_EOF)
break;
}
else {
timeout = TEST_SFTP_TIMEOUT;
}

if (ret == WS_FATAL_ERROR && error == 0) {
WOLFSSH_CHANNEL* channel =
Expand Down Expand Up @@ -1032,7 +1091,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,

if (readPending == 0) {
/* check if process is still running before waiting to read */
if (GetExitCodeProcess(processInfo.hProcess, &processState)
if (GetExitCodeProcess(processInfo.hProcess, &processState)
== TRUE) {
if (processState != STILL_ACTIVE) {
wolfSSH_Log(WS_LOG_INFO,
Expand Down Expand Up @@ -1690,6 +1749,7 @@ static void* HandleConnection(void* arg)

wolfSSH_set_fd(ssh, conn->fd);
wolfSSH_SetUserAuthCtx(ssh, conn->auth);
wolfSSH_SetChannelReqCtx(ssh, conn);

/* set alarm for login grace time */
graceTime = wolfSSHD_AuthGetGraceTime(conn->auth);
Expand Down Expand Up @@ -1737,15 +1797,14 @@ static void* HandleConnection(void* arg)
#endif
}

if (ret != WS_SUCCESS && ret != WS_SFTP_COMPLETE &&
ret != WS_SCP_INIT) {
if (ret != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Failed to accept WOLFSSH connection from %s error %d",
conn->ip, ret);
}
}

if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE || ret == WS_SCP_INIT) {
if (ret == WS_SUCCESS) {
WPASSWD* pPasswd = NULL;
WOLFSSHD_CONFIG* usrConf;
char* usr;
Expand All @@ -1761,8 +1820,7 @@ static void* HandleConnection(void* arg)
}

#ifndef WIN32
if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE ||
ret == WS_SCP_INIT) {
if (ret == WS_SUCCESS) {
pPasswd = getpwnam((const char *)usr);
if (pPasswd == NULL) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error getting user info");
Expand All @@ -1771,81 +1829,59 @@ static void* HandleConnection(void* arg)
}
#endif

if (ret != WS_FATAL_ERROR) {
/* check for any forced command set for the user */
switch (wolfSSH_GetSessionType(ssh)) {
case WOLFSSH_SESSION_SHELL:
#ifdef WOLFSSH_SHELL
if (ret == WS_SUCCESS) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Entering new shell");
SHELL_Subsystem(conn, ssh, pPasswd, usrConf, NULL);
}
#else
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Shell support is disabled");
ret = WS_NOT_COMPILED;
#endif
break;

case WOLFSSH_SESSION_SUBSYSTEM:
/* test for known subsystems */
switch (ret) {
case WS_SFTP_COMPLETE:
#ifdef WOLFSSH_SFTP
ret = SFTP_Subsystem(conn, ssh, pPasswd, usrConf);
#else
err_sys("SFTP not compiled in. Please use "
"--enable-sftp");
#endif
break;

case WS_SCP_INIT:
#ifdef WOLFSSH_SCP
ret = SCP_Subsystem(conn, ssh, pPasswd, usrConf);
#else
err_sys("SCP not compiled in. Please use "
"--enable-scp");
#endif
break;

default:
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Unknown or build not supporting sub"
"system found [%s]",
wolfSSH_GetSessionCommand(ssh));
ret = WS_NOT_COMPILED;
}
break;

case WOLFSSH_SESSION_UNKNOWN:
case WOLFSSH_SESSION_EXEC:
#if defined(WOLFSSH_SHELL)
if (ret == WS_SUCCESS) {
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Entering exec session [%s]",
wolfSSH_GetSessionCommand(ssh));
SHELL_Subsystem(conn, ssh, pPasswd, usrConf,
wolfSSH_GetSessionCommand(ssh));
}
#endif /* WOLFSSH_SHELL */

/* SCP can be an exec type */
if (ret == WS_SCP_INIT) {
#ifdef WOLFSSH_SCP
ret = SCP_Subsystem(conn, ssh, pPasswd, usrConf);
#else
err_sys("SCP not compiled in. Please use "
"--enable-scp");
#endif
}
break;
do {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs sanity check on ret value to account for error in getting user info, before entering do while loop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this handle a peer just closing down the socket and disconnecting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the client application authenticates the user then closes the socket, we should just close down. The client should also be able to send a MSG_DISCONNECT and the server should close out the connection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And you are right about the check on the return value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably should have been more clear about the peer just closing down. Disconnected as in the Ethernet wire was pulled or internet connection shut off. I think this do while loop would continue spinning on in that case since the channel is never opened?

ret = wolfSSH_worker(ssh, NULL);
} while (conn->channel == NULL);

case WOLFSSH_SESSION_TERMINAL:
default:
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Unknown or build not supporting session type "
"found");
ret = WS_NOT_COMPILED;
if (conn->doShell) {
#ifdef WOLFSSH_SHELL
if (ret == WS_SUCCESS) {
SHELL_Subsystem(conn, ssh, pPasswd, usrConf, NULL);
}
#else
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Shell support is disabled");
ret = WS_NOT_COMPILED;
#endif
}
else if (conn->doSftp) {
#ifdef WOLFSSH_SFTP
int select_ret;
do {
select_ret = tcp_select(conn->fd, 1);
if (select_ret == WS_SELECT_RECV_READY
|| select_ret == WS_SELECT_ERROR_READY
|| error == WS_WANT_WRITE) {
ret = wolfSSH_SFTP_accept(ssh);
error = wolfSSH_get_error(ssh);
}
else if (select_ret == WS_SELECT_TIMEOUT) {
error = WS_WANT_READ;
}
else {
error = WS_FATAL_ERROR;
}
} while (ret != WS_SFTP_COMPLETE
&& (error == WS_WANT_READ || error == WS_WANT_WRITE));
if (ret == WS_SFTP_COMPLETE) {
ret = SFTP_Subsystem(conn, ssh, pPasswd, usrConf);
}
#else
err_sys("SFTP not compiled in. Please use --enable-sftp");
#endif
}
else if (conn->doScp) {
#ifdef WOLFSSH_SCP
ret = SCP_Subsystem(conn, ssh, pPasswd, usrConf);
#else
err_sys("SCP not compiled in. Please use --enable-scp");
#endif
}
else if (conn->doExec) {
if (ret == WS_SUCCESS) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Entering exec session [%s]",
wolfSSH_GetSessionCommand(ssh));
SHELL_Subsystem(conn, ssh, pPasswd, usrConf,
wolfSSH_GetSessionCommand(ssh));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to have a final else case to log that an unknown/unsupported channel type was recieved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wolfSSHd's channel request callbacks set those flags after the channel is created, it's guaranteed. Having a channel pointer and none of the three "do" flags sets is definitely an error condition. Adding the else clause.

}
}
Expand Down Expand Up @@ -2053,7 +2089,7 @@ static void wolfSSHD_ServiceCb(DWORD CtrlCode)
static char* _convertHelper(WCHAR* in, void* heap) {
int retSz;
char* ret;

retSz = (int)wcslen(in) * 2;
ret = (char*)WMALLOC(retSz + 1, heap, DYNTYPE_SSHD);
if (ret != NULL) {
Expand Down Expand Up @@ -2399,7 +2435,8 @@ static int StartSSHD(int argc, char** argv)
SOCKADDR_IN_T clientAddr;
socklen_t clientAddrSz = sizeof(clientAddr);
#endif
conn = (WOLFSSHD_CONNECTION*)WMALLOC(sizeof(WOLFSSHD_CONNECTION), NULL, DYNTYPE_SSHD);
conn = (WOLFSSHD_CONNECTION*)WMALLOC(sizeof(WOLFSSHD_CONNECTION),
NULL, DYNTYPE_SSHD);
if (conn == NULL) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed to malloc memory for connection");
break;
Expand All @@ -2408,6 +2445,11 @@ static int StartSSHD(int argc, char** argv)
conn->auth = auth;
conn->listenFd = (int)listenFd;
conn->isThreaded = isDaemon;
conn->doShell = 0;
conn->doSftp = 0;
conn->doScp= 0;
conn->doExec = 0;
conn->channel = NULL;

/* wait for a connection */
if (PendingConnection(listenFd)) {
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ AM_CONDITIONAL([BUILD_KEYGEN],[test "x$ENABLED_KEYGEN" = "xyes"])
AM_CONDITIONAL([BUILD_SCP],[test "x$ENABLED_SCP" = "xyes"])
AM_CONDITIONAL([BUILD_SFTP],[test "x$ENABLED_SFTP" = "xyes"])
AM_CONDITIONAL([BUILD_FWD],[test "x$ENABLED_FWD" = "xyes"])
AM_CONDITIONAL([BUILD_TERM],[test "x$ENABLED_TERM" = "xyes"])
AM_CONDITIONAL([BUILD_TERM],[test "x$ENABLED_PTERM" = "xyes"])
AM_CONDITIONAL([BUILD_SHELL],[test "x$ENABLED_SHELL" = "xyes"])
AM_CONDITIONAL([BUILD_AGENT],[test "x$ENABLED_AGENT" = "xyes"])
AM_CONDITIONAL([BUILD_SSHD],[test "x$ENABLED_SSHD" = "xyes"])
Expand Down
Loading
Loading