The worker drops back to APP_STATE_LISTEN when an agent connection ends,
but never closes the socket. The next accept() overwrites agentFd, so
every agent connection after the first leaks the previous descriptor. The
forward path has the same gap on its connection-reset arm, where the
socket is closed but fwdFd keeps the closed number.
A rekey was treated as a read failure and ended the session. It cannot
just be skipped either: wolfSSH_worker() reports WS_REKEYING in place of
WS_CHAN_RXD while keying, and nothing raises the data report again, so
ignoring it strands whatever arrived in that call and the peer waits on
an answer that never comes. This is the hazard the library already calls
out for WS_EXTDATA, which is exempted from the same override.
- close agentFd and clear it on both the read-zero and the
ECONNRESET/ECONNABORTED arms
- clear fwdFd on the forward reset arm, matching the read-zero arm
- clear agentCtx.appFd and fwdCtx.appFd wherever the worker closes the
socket, so the stored copy cannot outlive the descriptor
- drain the channel on WS_REKEYING as well as WS_CHAN_RXD, and take an
empty read as "nothing buffered" rather than a failure on that path.
wolfSSH_ChannelIdRead() has no isKeying gate and the window credit it
owes is parked until the rekey completes
ES_ERROR() passes its arguments straight to fprintf(stderr, ...), so a
message with no trailing newline runs into whatever the shell or the
test harness prints next.
- 7 sites in the echoserver, 6 in tests/auth.c, 8 in the Espressif copy
of the echoserver, which carries the same macro and takes this kind of
cross-cutting fix (e91ff50d, ab8058d7)
- the two wrapped format strings already ended with a newline
- The startup banner's password line and its argument are dropped
from the printf; ssh host, username and the two forward endpoints
remain.
- userPassword has internal linkage, and portfwd_worker() zeroes it
with wc_ForceZero() as soon as wolfSSH_connect() returns, on both
the success and the failure path.
- portfwd.c includes wolfssl/wolfcrypt/memory.h.
Issue: F-11673
- Add wolfSSH_SFTP_SetConfinePath and a separate sftpConfinePath, so
the start path only says where a session begins, and only an
explicit confinement root rejects out-of-tree requests.
- Have GetAndCleanPath take the WOLFSSH and enforce the confinement
root, resolving relative requests against the start path.
- Factor the shared canonicalize-and-store work out of
wolfSSH_SFTP_SetDefaultPath into CanonicalizePath and StorePath.
- Give the echoserver -D to opt a session into confinement; without
it the -d home directory only says where SFTP starts.
- Document both settings, and the symlink and TOCTOU caveats, once in
wolfsftp.h, noting the confinement root itself is trusted.
- Cover the split in api.c, and in regress.c start a session in a
subdirectory of the confinement root: a sibling of the start
directory is reachable, anything above the root is not.
Issue: ZD-22308
The scripts now read the build options from the probe instead of grepping
usage text, config.log and daemon logs. Drops the usage lines only tests read.
- sftpclient passes userEcc to ClientUsePubKey(), and scpclient to
both ClientSetPrivateKey() and ClientUsePubKey(), in place of a
hardcoded 0.
- scpclient gains a userEcc; it and client default it to 1 under
WOLFSSH_NO_RSA, as sftpclient already did.
- ClientSetPrivateKey() and ClientUsePubKey() name the missing
algorithm on stderr and return WS_NOT_COMPILED when the built-in
key they select is compiled out.
- Both skip the built-in load entirely when neither RSA nor ECC is
compiled in, clearing the key size and type and returning success
so password-only authentication still runs. ClientUsePubKey()'s
buffer pointer moves inside the guard so it is not left unused.
Issue: F-8829
- store select()'s result in an int so an error is not read
as a large positive count
- retry on EINTR, bail out on any other error
- re-arm the descriptor sets on every pass
Issue: F-7508
- zero the response arrays and stop filling after the first
failed read, tracking only the slots populated
- release the previous round's responses on each INFO_REQUEST
- add auth.test coverage for EOF stdin and a second round
Issue: F-7515, F-7516
The loop condition already guarantees a want-read or want-write error,
so the select_ret arms of the retry test and the else chain could never
run. Retry unconditionally; tcp_select still throttles the loop. Same
change applied to the copy in apps/wolfssh/wolfssh.c.
Issue: CID-572884
Both loop exits in readInput() returned early, leaving the per-thread
ECC cache cleanup after the loop unreachable. Break out of the loop
instead.
wolfSSH_stream_send() reports a rekey in progress by returning
WS_FATAL_ERROR with the ssh error set to WS_REKEYING, so testing the
return value against WS_REKEYING never matches. Read the code with
wolfSSH_get_error() and resend the same buffer once the rekey
finishes, in both the app and the example client. Looping back to
read() instead would drop the input already taken from stdin.
Issue: CID-572833
- Gate header on new scpFileHeaderSent flag, not scpFileOffset==0
- A send callback returning 0 bytes first no longer re-sends header
- Skip zero-length SCP_SEND_FILE send to avoid empty CHANNEL_DATA
- Abort on a second consecutive 0-byte send callback return with file
data outstanding; skipping the send would otherwise spin
SCP_SEND_FILE -> SCP_TRANSFER with no socket I/O
- Reset offset/bufferedSz/flags in ScpSourceInit for connection reuse
- Document the WS_CallbackScpSend contract, including when a 0 return
is valid, next to the typedef
- Add test_wolfSSH_SCP_SendZeroFirst regression (func_args scp_send hook)
- Zero func_args in kex.c/testsuite.c so the new scp_send field is not read uninitialized
Issue: ZD-22176
The send at the end of the loop only ran when select() reported a
readable descriptor, but appBuffer can hold data across iterations.
Mask appFd out of the read set while the buffer is full, and fall
through the select() timeout to the send.
Issue: F-7207
- Track userPublicKey allocations with a userPublicKeyAlloc flag
- Free on that flag, not pubKeyName; -J with no -j leaked the cert
- Restore userPublicKeyBuf when a key load fails, not a stale pointer
- Tag load_der_file() allocations DYNTYPE_PRIVKEY to match the frees
- Free the CA cert in ClientLoadCA() with the heap it came from
- Pass the caller's heap into wolfSSH_TPM_InitKey() so the TPM public
key is allocated from the pool ClientFreeBuffers() frees it with
Issue: F-7210, F-7211
- Test wolfSSH_ReadKey_buffer() and wc_CertPemToDer() results and skip
the entry; a malformed file gave PwMapNew() a NULL buf and an
indeterminate length.
- NULL-check both WMALLOC() results, and guard the load_file() size so
a missing file no longer reaches WMALLOC(0).
- Fall through to the loop's existing WFREE()/advance so both buffers
are freed on every path.
Issue: F-7204
- wolfSSH_ChannelSend() can return fewer bytes than requested, but
appBufferUsed was decremented without moving the unsent tail to the
front of appBuffer, corrupting subsequent sends. Shift the remaining
data down with WMEMMOVE() when the send is short.
- Skip the recv() when appBuffer is full. The length argument would be
0, and a zero length recv() returns 0, which the loop read as the
peer closing; the buffered data was dropped and the forward torn
down.
Issue: F-7207
- ssh_worker() cached fwdCtx.listenFd at entry, while still -1
- The listener is only made later, from WOLFSSH_FWD_REMOTE_SETUP
- FD_SET() and accept() then got a bogus fd, failing with EBADF,
which broke the worker loop and dropped the session
- Read listenFd from the context at each use, guarded on validity
- agentListenFd has the same shape but is set up before ssh_worker()
Issue: ZD-21867
- Add wolfSSH_FwdRemoteSetup/Cancel to request tcpip-forward
- Add SendGlobalRequestFwd to frame the request per RFC 4254
- Add portfwd -r reverse mode, driven by the fwd and req-success cbs
- Wait for the peer's reply before -R reports ready, and take the
bound port from it; with -f 0 that reply is the only source
- Accept -f 0 in reverse mode, where it asks the peer to pick the port
- Cancel names the port the peer bound, not the one requested, so a
peer keyed on its listener's port can still find it
- Add a req-failure cb so a refused forward is reported, not waited on
Issue: ZD-21867
Keyboard-interactive was unusable in builds with
WOLFSSH_KEYBOARD_INTERACTIVE but no WOLFSSH_TERM, in two ways.
- ClientFreeBuffers declared 'entry' under TERM && KBI but used it
under KBI alone, so KBI-without-TERM failed to compile; widen the
declaration guard to match the use
- ClientUserAuth's keyboard-interactive branch is guarded on
TERM && KBI, so without TERM a keyboard-interactive request fell
past every branch and returned the initial WOLFSSH_USERAUTH_SUCCESS
with no responses populated. There is no terminal to prompt on, so
answer WOLFSSH_USERAUTH_FAILURE instead of claiming success.
- Reply to a port-0 (dynamic) tcpip-forward with the bound port.
- Add WS_FWD_PORT_CHECK (1024) as the status/port boundary in WS_FwdCbError.
- Callback returns a WS_FwdCbError status below it, the port at or above it.
- DoGlobalRequestFwd reports the port and rejects a port-0 setup with none.
- Map a callback rejection to WS_RESOURCE_E so a no-reply request keeps the link.
- Update the echoserver reference callbacks (examples and Espressif) to
recover the OS-chosen port with getsockname() and return it under the new
convention.
- Add regress coverage for the allocated-port and rejection paths.
Issue: F-5573
Co-authored-by: John Safranek <john@wolfssl.com>
1. Remove the check on authType, it is covered already.
2. Add Keyboard Setup to the existing check on authType.
3. Add a branch for User Auth None so it reaches its handler
in the map loop rather than the new error case.
4. Add else case for an error.
Fixes CID: 637345
Cleanup clang-tidy bugprone-signal-handler findings.
- wolfsshd: drop fprintf from interruptCatch; the main accept
loop logs "Closing down wolfSSHD" after seeing quit set.
- sftpclient: annotate wolfSSH_SFTP_Interrupt call in
sig_handler with NOLINT, since the function is only a single
byte store and is safe to call from a signal handler.
- Zero private key and password buffers in both apps/wolfssh
and examples client.
- Also zero keyboard-interactive response buffers in the
example client.
Issue: F-249