echoserver: bind sftp and scp as the library does

The subsystem and exec callbacks pick out the same commands the accept
state machine does: sftp matched whole, by length and bytes, and scp on
the three-byte prefix ChannelCommandIsScp() takes.

- sftp with an embedded NUL is refused, rather than granted and then
  dropped by wolfSSH_SFTP_accept()
- a transfer is granted only on the head channel the accept APIs serve,
  so a request on a later channel is refused rather than answered
  success
pull/1254/head
John Safranek 2026-09-11 13:58:24 -07:00 committed by Paul Adelsbach
parent eef5346f7f
commit ecb79ea4e3
1 changed files with 29 additions and 5 deletions

View File

@ -768,6 +768,19 @@ static int SessionInUse(const thread_ctx_t* threadCtx)
} }
#if defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)
/* wolfSSH_SFTP_accept() and wolfSSH_SCP_accept() work from the head of the
* channel list, so a transfer granted on any other channel answers the peer
* success and then runs against the wrong one. The shell has no such limit:
* its callback keeps the channel id. */
static int TransferChannel(const thread_ctx_t* threadCtx,
WOLFSSH_CHANNEL* channel)
{
return channel == wolfSSH_ChannelNext(threadCtx->ssh, NULL);
}
#endif /* WOLFSSH_SFTP || WOLFSSH_SCP */
/* Registered in every build, in both modes: with no shell the echoserver /* Registered in every build, in both modes: with no shell the echoserver
* still has to take the channel to mark it connected, so ssh_worker() will * still has to take the channel to mark it connected, so ssh_worker() will
* echo on it. Returns WS_SUCCESS to accept the request, 1 to reject it. */ * echo on it. Returns WS_SUCCESS to accept the request, 1 to reject it. */
@ -919,9 +932,15 @@ static int wsSubsysStartCb(WOLFSSH_CHANNEL* channel, void* vCtx)
type = wolfSSH_ChannelGetSessionType(channel); type = wolfSSH_ChannelGetSessionType(channel);
/* A truncated subsystem string leaves the command NULL, and this /* A truncated subsystem string leaves the command NULL, and this
* runs before anything else has looked at it. */ * runs before anything else has looked at it. The name matches
* whole, length and bytes, as wolfSSH_SFTP_accept() asks: granting
* sftp with an embedded NUL answers success on a session it then
* refuses. */
if (type == WOLFSSH_SESSION_SUBSYSTEM && cmd != NULL if (type == WOLFSSH_SESSION_SUBSYSTEM && cmd != NULL
&& WSTRCMP(cmd, "sftp") == 0) { && wolfSSH_ChannelGetSessionCommandSz(channel)
== (word32)WSTRLEN("sftp")
&& WSTRCMP(cmd, "sftp") == 0
&& TransferChannel(threadCtx, channel)) {
threadCtx->doSftp = 1; threadCtx->doSftp = 1;
rej = WS_SUCCESS; rej = WS_SUCCESS;
} }
@ -946,9 +965,14 @@ static int wsExecStartCb(WOLFSSH_CHANNEL* channel, void* vCtx)
} }
#ifdef WOLFSSH_SCP #ifdef WOLFSSH_SCP
if (cmd != NULL && WSTRNCMP(cmd, "scp ", 4) == 0) { /* The prefix ChannelCommandIsScp() matches, so both modes agree. */
((thread_ctx_t*)vCtx)->doScp = 1; if (cmd != NULL && WSTRNCMP(cmd, "scp", 3) == 0) {
rej = WS_SUCCESS; /* An scp command the transfer cannot be run for is refused
* rather than served as a session. */
if (TransferChannel((thread_ctx_t*)vCtx, channel)) {
((thread_ctx_t*)vCtx)->doScp = 1;
rej = WS_SUCCESS;
}
} }
else else
#endif /* WOLFSSH_SCP */ #endif /* WOLFSSH_SCP */